Пример #1
0
def plot_route(map_components, route_ends, segments, path_indices):
    """
    Plot a route on top of a (already) plotted map

    Inputs:
        map_components is a pd.DataFrame with the raw NYC data
        route_ends is a list of 2 str with the form lon_lat each
        segments is a pd.DataFrame with the processed segments
        path indices is a list of the rows in segments that are part of the
            route
    """
    # plotting the map
    subplot_axes = plot_raw_data(map_components)  # ,
    #                              xlim=[-73.985, -73.955],
    #                              ylim=[40.760, 40.785])

    # plots starting and end point
    lon_start, lat_start = names.name_to_lon_lat(route_ends[0])
    pl.plot(lon_start, lat_start, 's', color='#ff33cc', markersize=12)
    lon_end, lat_end = names.name_to_lon_lat(route_ends[1])
    pl.plot(lon_end, lat_end, 'o', color='#ff33cc', markersize=12)

    # plotting the route
    if path_indices is not None:
        segments_gpd = gpd.GeoDataFrame(segments)
        route = segments_gpd.iloc[np.array(path_indices)]
        route.plot(ax=subplot_axes, color='k', linewidth=4)
    pl.savefig('path_run.png')
Пример #2
0
def select_random_point_pairs(segments, target_distance, n_pairs=1):
    """
    Fill me
    """
    # list of possible vertexes
    vertex_list = [
        v for i, v in enumerate(segments['vertex_start'].values)
        if segments['type'].iloc[i] == 'street'
    ]
    vertex_list = [
        v for i, v in enumerate(segments['vertex_end'].values)
        if segments['type'].iloc[i] == 'street'
    ]
    all_vertex = set(vertex_list)
    all_vertex = np.array([i for i in all_vertex])

    # select n_pairs random indexes
    start_indexes = np.floor(np.random.rand(n_pairs) * len(all_vertex))
    start_indexes = start_indexes.astype(int)

    # find the points corresponding to the indices
    start_points = all_vertex[start_indexes]

    # getting lon and lat for all vertex
    all_vertex_lon_lat = {'lon': [], 'lat': []}
    for index, vertex in enumerate(all_vertex):
        lon, lat = names.name_to_lon_lat(vertex)
        all_vertex_lon_lat['lon'].append(lon)
        all_vertex_lon_lat['lat'].append(lat)
    all_vertex_lon_lat['lon'] = np.array(all_vertex_lon_lat['lon'])
    all_vertex_lon_lat['lat'] = np.array(all_vertex_lon_lat['lat'])

    end_points = []
    for start_point in start_points:
        lon, lat = names.name_to_lon_lat(start_point)
        ang_dist_to_pt = angles.ang_dist(lon, lat, all_vertex_lon_lat['lon'],
                                         all_vertex_lon_lat['lat'])
        dist_to_pt = angles.convert_distance_to_physical(ang_dist_to_pt, 'km')
        valid = np.logical_and(dist_to_pt > 0., dist_to_pt < target_distance)

        index = int(np.floor(np.random.rand(1) * valid.sum())[0])
        end_points.append(all_vertex[valid][index])

    # points
    pts = []
    for i in range(n_pairs):
        pts.append((start_points[i], end_points[i]))

    return pts
Пример #3
0
def select_random_point(segments, start_point, target_distance, units):
    """
    Select a random point in segments withing a distance

    Input:
        segments is a pd.DataFrame with all the segments to consider
        start_point is a string 'lon_lat' that we are centered on
        target_distance is a radius to consider, the point must be inside

    Output:
        end_point is the string 'lon_lat' that was selected
    """
    # list of possible vertexes
    vertex_list = [
        v for i, v in enumerate(segments['vertex_start'].values)
        if segments['type'].iloc[i] == 'street'
    ]
    vertex_list = [
        v for i, v in enumerate(segments['vertex_end'].values)
        if segments['type'].iloc[i] == 'street'
    ]
    all_vertex = set(vertex_list)
    all_vertex = np.array([i for i in all_vertex])

    # getting lon and lat for all vertex
    all_vertex_lon_lat = {'lon': [], 'lat': []}
    for index, vertex in enumerate(all_vertex):
        lon, lat = names.name_to_lon_lat(vertex)
        all_vertex_lon_lat['lon'].append(lon)
        all_vertex_lon_lat['lat'].append(lat)
    all_vertex_lon_lat['lon'] = np.array(all_vertex_lon_lat['lon'])
    all_vertex_lon_lat['lat'] = np.array(all_vertex_lon_lat['lat'])

    # randmomly selectend point
    lon, lat = names.name_to_lon_lat(start_point)
    ang_dist_to_pt = angles.ang_dist(lon, lat, all_vertex_lon_lat['lon'],
                                     all_vertex_lon_lat['lat'])
    dist_to_pt = angles.convert_distance_to_physical(ang_dist_to_pt, units)
    valid = np.logical_and(dist_to_pt > 0., dist_to_pt < target_distance)

    index = int(np.floor(np.random.rand(1) * valid.sum())[0])
    end_point = all_vertex[valid][index]

    return end_point
Пример #4
0
def get_closest_point_to(lon0, lat0, intersection_list):
    """
    from a list of intersections (['lon_lat', ...]), returns the closest point
    to (lon, lat)
    Assumes all angles in degrees
    """
    locations = {'lon': [], 'lat': [], 'd': []}
    for name_ in intersection_list:
        lon, lat = names.name_to_lon_lat(name_)
        locations['lon'].append(lon)
        locations['lat'].append(lat)
        locations['d'].append(
            angles.ang_dist(angles.deg_to_rad(lon0), angles.deg_to_rad(lat0),
                            angles.deg_to_rad(lon), angles.deg_to_rad(lat)))
    index_closest_point = np.argmin(np.array(locations['d']))
    return intersection_list[index_closest_point]
Пример #5
0
    def run(self,
            route_ends,
            target_dist,
            units='km',
            algorithm_type='dijkstra',
            cost_weights=None):
        """
        """
        segments = self.data_hand.load_processed_data()

        # list of all possible intersections
        intersection_names = list(segments['vertex_start'].values)
        intersection_names += list(segments['vertex_end'].values)
        intersection_names = list(set(intersection_names))

        # get closest intersection to provided points
        start_point_lon, start_point_lat = names.name_to_lon_lat(route_ends[0])
        end_point_lon, end_point_lat = names.name_to_lon_lat(route_ends[1])
        start_point = locations.get_closest_point_to(start_point_lon,
                                                     start_point_lat,
                                                     intersection_names)
        end_point = locations.get_closest_point_to(end_point_lon,
                                                   end_point_lat,
                                                   intersection_names)
        route_ends = [start_point, end_point]
        print("Optimizing route from {0:s} to {1:s}".format(
            start_point, end_point))

        # load data for plotting
        dfs = {}
        processed_path = os.path.join(self.running_heaven_path, 'data',
                                      'processed')
        for key_ in ['park', 'street', 'sidewalk']:
            geojson_file_name = '{0:s}.geojson'.format(key_)
            dfs[key_] = gpd.read_file(
                os.path.join(processed_path, geojson_file_name))
        dfs['tree'] = pd.read_csv(os.path.join(processed_path, 'tree.csv'))

        # updating dataframe
        segments['tree_density_weight'] = 1. - segments['tree_density']
        target_dist_deg = angles.convert_distance_to_degree(target_dist, units)
        park_weight = self.define_park_weight(
            segments,  # dfs['park'],
            target_dist_deg)
        segments['park_weight'] = park_weight

        # distribution of features for debugging
        # self.feature_distributions(tree_density_norm, park_weight)

        # linear programming solution
        if algorithm_type == 'integer_programming':
            path_indices, d_path = self.integer_programming(
                segments, units, (start_point, end_point), target_dist)
        elif algorithm_type == 'dijkstra':
            # problem information for Dijkstra's algorithm
            # add the segments in the reverse direction as well
            edges = []
            segments_copy = copy.deepcopy(segments)
            vertex_start = copy.deepcopy(segments_copy['vertex_start'])
            vertex_end = copy.deepcopy(segments_copy['vertex_end'])
            segments_copy['vertex_start'] = vertex_end
            segments_copy['vertex_end'] = vertex_start
            segments = segments.append(segments_copy)
            segments.reset_index(drop=True, inplace=True)

            for index in segments.index.astype(int):
                # distance - shortest path
                tree_weight = segments['tree_density_weight'].iloc[index]
                park_weight = segments['park_weight'].iloc[index]
                intersection = int(segments['type'].iloc[index] == 'street')
                segment_info = {
                    'distance': segments['distance'].iloc[index],
                    'tree_density_weight': tree_weight,
                    'park_weight': park_weight,
                    'intersection': intersection
                }

                # (starting point, end point, cost, segment_info
                edges.append(
                    (segments['vertex_start'].iloc[index],
                     segments['vertex_end'].iloc[index], 0., segment_info))

            # try different cost term weights
            choices = [0.1, 10.]
            weights = [
                np.array(p) for p in itertools.product(choices, repeat=5)
            ]
            # set fixed values if provides
            # distance, spiral, tree, park, intersection
            if cost_weights is not None:
                fixed = ~np.isnan(cost_weights)
                for weight in weights:
                    weight[fixed] = np.array(cost_weights)[fixed]
                weights = [list(i) for i in weights]

                # remove duplicates
                for i in range(len(weights) - 1, -1, -1):
                    if weights.count(weights[i]) > 1:
                        weights.pop(i)

            # iterate on the different weights
            path_indices_list = []
            d_path_list = []
            cost_list = []
            for weight in weights:
                opt_path = self.dijkstra(edges, start_point, end_point,
                                         target_dist_deg, weight)

                if opt_path[0] == 0.:
                    print('Warning: impossible route')
                    return None, None, None

                # get indices from path
                path_indices, d_path = self.get_indices_from_path(
                    opt_path, start_point, segments)
                d_path = angles.convert_distance_to_physical(d_path, units)
                path_indices_list.append(path_indices)
                d_path_list.append(d_path)
                cost_list.append(opt_path[0])
                # print(weight, cost_list[-1], d_path)

            distance_difference = abs(np.array(d_path_list) - target_dist)
            index_closest_distance = np.argmin(distance_difference)
            d_path = d_path_list[index_closest_distance]
            path_indices = path_indices_list[index_closest_distance]
        else:
            exit('Analysis types 1 and 2 defined so far.')

        # plotting the data and route
        if self.show:
            map_plotter.plot_route(dfs, route_ends, segments, path_indices)

        # resulting distance
        print('Total distance is : {0:f} {1:s}'.format(d_path, units))
        print('Taget distance was: {0:f} {1:s}'.format(target_dist, units))

        if self.show:
            pl.show()

        route_lon_lat = self.get_route(segments, path_indices, start_point,
                                       end_point)

        return d_path, route_lon_lat, segments.iloc[path_indices]
Пример #6
0
    def update_costs(self, object_, target_d, d_done, current_point, end_point,
                     weight):
        """
        updates the costs in the defaultdict

        object_ is g in the dijkstra function
        target_d is the length of the intended run
        d_done is the dictionary of lengths so far for the routes

        cost function: ((d_left - d0) / d0)^2 * cos(theta_between_pt_and end)
                       ( 1 - (d_left - d0) / d0)^2 * tree_density_normalized

        Right now, sets all to 0
        """
        lon_end, lat_end = names.name_to_lon_lat(end_point)
        lon_current, lat_current = names.name_to_lon_lat(current_point)
        theta_end = locations.get_angle(lon_current, lat_current, lon_end,
                                        lat_end)

        for key_ in [current_point]:
            for i in range(len(object_[key_])):
                temp = list(object_[key_][i])
                lon, lat = names.name_to_lon_lat(object_[key_][i][1])

                # cost function
                dist_ran = temp[2]['distance'] + d_done[current_point]
                theta_pt = locations.get_angle(lon_current, lat_current, lon,
                                               lat)
                theta_diff = theta_end - theta_pt
                d_direct = angles.ang_dist(lon_current, lat_current, lon, lat)
                dist_left = target_d - dist_ran

                # cost function increases as run ends and is directed towards
                # the end point, has lower cost towards the end point
                # r_factor should be between 0 (start, dist_ran=0) and
                # 1 (end, dist_ran=target_d) if dist_ran < target_d:
                dist_frac = 0.5
                if dist_ran < dist_frac * target_d:
                    r_factor = (dist_ran / (dist_frac * target_d / 2.))
                else:
                    r_factor = 1.
                # no cost as long as we have not reached the proper length
                if dist_left > d_direct:
                    cost_dist = 0.
                else:
                    cost_dist = r_factor**2
                    cost_dist *= ((1. + np.cos(np.pi + theta_diff)) / 2.)**2

                # spiral term when far
                cost_dist2 = (1. - r_factor)**2
                # cost_dist2 *= ((1. + np.cos(2.*theta_diff))/2.)**2
                cost_dist2 *= ((1. + np.cos(theta_diff)) / 2.)**2

                # tree weight
                cost_tree = (1. - r_factor)**2
                cost_tree *= (temp[2]['tree_density_weight'])**2
                # less cost for routes towards parks
                cost_park = (1. - r_factor)**2 * temp[2]['park_weight']**2

                # cost_intersection = (1. - r_factor)**2 *
                #                      temp[2]['intersection']**2
                cost_intersection = temp[2]['intersection']**2

                cost_terms = [
                    weight[0] * cost_dist, weight[1] * cost_dist2,
                    weight[2] * cost_tree, weight[3] * cost_park,
                    weight[4] * cost_intersection
                ]

                temp[0] = copy.deepcopy(np.sum(cost_terms))
                object_[key_][i] = temp
        return object_