def get_population_points(self, lat: float, lon: float, range_km: float, interval_km: float) \ -> Tuple[List[Tuple[float, float]], List[float]]: """ Get the coordinates of dummy wards with weights as the population density around the corresponding point. Both ``range_km`` and ``interval_km`` will be used for generating dummy wards. This method gets 3 closest ward points centered around ``(lat, lon)``, then use these to construct a plane to project the population density, which will be returned as the second element. """ pop_points = self.find_closest_data_num(lat, lon, 3) pop_project_plane = get_plane( ((pop_points[0].data.lat, pop_points[0].data.lon, pop_points[0].data.total), (pop_points[1].data.lat, pop_points[1].data.lon, pop_points[1].data.total), (pop_points[2].data.lat, pop_points[2].data.lon, pop_points[2].data.total))) ret_pop_points: List[Tuple[float, float]] = [] ret_pop_density: List[float] = [] wards = generate_points((lat, lon), range_km, interval_km) for ward in wards: ret_pop_points.append(ward) ret_pop_density.append(pop_project_plane.get_z(*ward, 1)) return ret_pop_points, ret_pop_density
def get_all_stop_remove_results(self, range_km: float, interval_km: float, pop_data: Optional[PopulationDataController] = None) \ -> List[CrossStopRemovalResult]: """ Try to remove each stops one by one, and return the results of the removal. Specify ``pop_data`` to use the population data instead of dummy agents for calculating the distances. This function uses ``msnmetrosim.utils.generate_points()`` to generate simulated agents and to calculate the accessibility impact. The ``center_coord`` of ``msnmetrosim.utils.generate_points()`` will be the coordinates of the stop. Check the documentation of ``msnmetrosim.utils.generate_points()`` for more information on ``range_km`` and ``interval_km``. WARNING: This method could be very expensive. For 1153 records, it takes ~5 mins to run. """ # ThreadPoolExecutor won't help on performance boosting # OPTIMIZE: Try to reduce the calculation time of this # - Each agent is expanding its circle to find the closest stop # - Change the above to each stop expanding its circle to "touch" the closest agent instead? # - Any possible use of numpy for performance boost? ret: List[CrossStopRemovalResult] = [] total_count = len(self.all_data) progress = Progress(total_count) progress.start() for stop in self.all_data: stop: MMTStopsAtCross agents: List[Tuple[float, float]] weights: Optional[List[float]] if pop_data: lat, lon = stop.coordinate agents, weights = pop_data.get_population_points(lat, lon, range_km, interval_km) else: agents = generate_points(stop.coordinate, range_km, interval_km) weights = None rm_result = self.get_metrics_of_single_stop_removal(stop.primary, stop.secondary, agents, weights) ret.append(rm_result) progress.rec_completed_one() print(progress) return ret
def plot_accessibility_impact_histograms(stops_name: List[Tuple[str, str]], plot_x: int, plot_y: int, range_km: float, interval_km: float, title: str): """ Plot the accessibility difference of before and after removing the stops onto a figure and return it. Each element of ``stops_name`` contains the first and second street (order doesn't matter) name. ``plot_x`` x ``plot_y`` must equal to the count of ``stops_cross``. :param stops_name: street pair of the stops to be removed :param plot_x: count of plots on x axis :param plot_y: count of plots on y axis :param range_km: range for the dummy agents to generate in km :param interval_km: dummy agents interval in km :param title: title of the main plot """ # pylint: disable=too-many-arguments # Get metrics between before and after removing the stop results: List[CrossStopRemovalResult] = [] for stop in get_stops_at_cross(stops_name): print(f"Getting the metrics of {stop.cross_name}") agents = generate_points(stop.coordinate, range_km, interval_km) result = ctrl_stops_cross.get_metrics_of_single_stop_removal( stop.primary, stop.secondary, agents) results.append(result) # Plot the data figure = generate_accessibility_plot_canvas(plot_x, plot_y, plot_stop_accessibility_hist, results) figure.suptitle( title, y=0.99, fontsize=20) # Enlarging the text and slightly reposition the title return figure
def get_distance_to_stop(): """Get the travel time to ``target_stop``.""" # Controllers to traverse target_stop = ctrl_stops_cross.get_grouped_stop_by_street_names( "Inwood", "Open Wood") stop_cross_no_target = ctrl_stops_cross.duplicate( lambda data: data.unique_cross_id != target_stop.unique_cross_id) # Create simulated agents sim_agents = generate_points(target_stop.coordinate, 0.5, 0.02) # Get the distance metrics metrics_original = ctrl_stops_cross.get_distance_metrics_to_closest( sim_agents, name="Original") metrics_after = stop_cross_no_target.get_distance_metrics_to_closest( sim_agents, name="Original") # ----- Plot histogram # https://datavizpyr.com/overlapping-histograms-with-matplotlib-in-python/ # Configure plot plt.figure(figsize=(10, 10)) plt.xlabel("Distance to stop (km)", size=14) plt.ylabel("Agent count", size=14) plt.title( f"Distance to stop change between before and after removing {target_stop.cross_name}" ) # Plot histogram plt.hist(metrics_original.data, bins=20, alpha=0.5, label="Original") plt.hist(metrics_after.data, bins=20, alpha=0.5, label="After") # Output plot image plt.legend(loc="upper right") plt.savefig("../assets/reports/0921-5.png") # Save the figure plt.show()