Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions examples/quickstart-fr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
import dotenv
import logging

import mobility

import polars as pl

dotenv.load_dotenv()


mobility.set_params(
# package_data_folder_path=os.environ["MOBILITY_PACKAGE_DATA_FOLDER"],
# project_data_folder_path=os.environ["MOBILITY_PROJECT_DATA_FOLDER"]
package_data_folder_path="D:/mobility-data",
project_data_folder_path="D:/test-09",
debug=False
)

# Using Foix (a small town) and a limited radius for quick results
transport_zones = mobility.TransportZones("fr-09122", radius = 10)

# Using EMP, the latest national mobility survey for France
emp = mobility.EMPMobilitySurvey()

# Creating a synthetic population of 1000 for the area
pop = mobility.Population(transport_zones, sample_size = 1000)

modes = [mobility.CarMode(transport_zones), mobility.WalkMode(transport_zones), mobility.BicycleMode(transport_zones)]
surveys = [emp]
motives = [mobility.HomeMotive(), mobility.WorkMotive(), mobility.OtherMotive(population=pop)]


# Simulating the trips for this population for three modes : car, walk and bicyle, and only home and work motives (OtherMotive is mandatory)
pop_trips = mobility.PopulationTrips(
pop,
modes,
motives,
surveys,
parameters=mobility.PopulationTripsParameters(n_iterations=4, k_mode_sequences=42)
)

pop_trips_base = mobility.PopulationTrips(
pop,
modes,
motives,
surveys,
parameters=mobility.PopulationTripsParameters(n_iterations=4, seed=49283092, k_mode_sequences=42)
)

tz = transport_zones.get()


# You can get the weekday trips to inspect them
weekday_flows = pop_trips.get()["weekday_flows"].collect()
weekday_flows_base = pop_trips_base.get()["weekday_flows"].collect()

# You can also plot the flows, with labels for the cities that are bigger than their neighbours
labels=pop_trips.get_prominent_cities()

# You can can also get global metrics that will be compared to the theoetical values for this population
cost_per_person = pop_trips.evaluate("cost_per_person", plot_delta=True, compare_with=pop_trips_base, labels=labels, plot=True)
dist_per_person = pop_trips.evaluate("distance_per_person", plot_delta=True, compare_with=pop_trips_base, plot=True)
time_per_person = pop_trips.evaluate("time_per_person", plot_delta=True, compare_with=pop_trips_base, plot=True)
ghg_per_person = pop_trips.evaluate("ghg_per_person", plot_delta=True, compare_with=pop_trips_base, plot=True)
global_metrics = pop_trips.evaluate("global_metrics")


pop_trips.plot_modal_share(mode="public_transport", labels=labels)
pop_trips.plot_modal_share(mode="bicycle")
pop_trips.plot_modal_share(mode="walk")
cms = pop_trips.plot_modal_share(mode="car")

# OD flows between transport zones
pop_trips.plot_od_flows(mode="car", level_of_detail=1, labels=labels)
pop_trips.plot_od_flows(mode="walk", level_of_detail=1)
pop_trips.plot_od_flows(mode="bicycle", level_of_detail=1)
pop_trips.plot_od_flows(mode="public_transport")
40 changes: 0 additions & 40 deletions examples/quickstart-fr.py.py

This file was deleted.

4 changes: 3 additions & 1 deletion mobility/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .set_params import set_params

from .model_parameters import Parameter, ParameterSet

from .study_area import StudyArea
from .transport_zones import TransportZones

Expand Down Expand Up @@ -31,7 +33,7 @@

from .cost_of_time_parameters import CostOfTimeParameters

from .choice_models.transport_mode_choice_model import TransportModeChoiceModel
#from .choice_models.transport_mode_choice_model import TransportModeChoiceModel
from .parsers import LocalAdminUnits


Expand Down
6 changes: 3 additions & 3 deletions mobility/choice_models/destination_sequence_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ def run(
transport_zones,
remaining_sinks,
costs,
parameters.cost_uncertainty_sd
parameters["cost_uncertainty_sd"]
)

dest_prob = self.get_destination_probability(
utilities,
motives,
parameters.dest_prob_cutoff
parameters["dest_prob_cutoff"]
)

chains = (
Expand All @@ -74,7 +74,7 @@ def run(
)

chains = self.spatialize_anchor_motives(chains, dest_prob, seed)
chains = self.spatialize_other_motives(chains, dest_prob, costs, parameters.alpha, seed)
chains = self.spatialize_other_motives(chains, dest_prob, costs, parameters["alpha"], seed)

dest_sequences = (
chains
Expand Down
67 changes: 38 additions & 29 deletions mobility/choice_models/population_trips.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def __init__(
"motives": motives,
"modes": modes,
"surveys": surveys,
"parameters": parameters
"parameters": parameters.to_dict()
}

project_folder = pathlib.Path(os.environ["MOBILITY_PROJECT_DATA_FOLDER"])
Expand All @@ -173,7 +173,9 @@ def __init__(
}

super().__init__(inputs, cache_path)


def has_multiple_seeds(self):
return (len(self.parameters.seeds) > 1)

def resolve_parameters(
self,
Expand Down Expand Up @@ -299,7 +301,7 @@ def create_and_get_asset(self):

demand_groups.write_parquet(self.cache_path["demand_groups"])

if self.parameters.simulate_weekend:
if self.parameters["simulate_weekend"]:

weekend_flows, weekend_sinks, demand_groups, weekend_costs, weekend_chains = self.run_model(is_weekday=False)

Expand Down Expand Up @@ -370,7 +372,7 @@ def run_model(self, is_weekday):

remaining_sinks = sinks.clone()

for iteration in range(1, parameters.n_iterations+1):
for iteration in range(1, parameters["n_iterations"]+1):

logging.info(f"Iteration n°{iteration}")

Expand Down Expand Up @@ -421,7 +423,7 @@ def run_model(self, is_weekday):
costs = self.state_updater.get_new_costs(
costs,
iteration,
parameters.n_iter_per_cost_update,
parameters["n_iter_per_cost_update"],
current_states_steps,
costs_aggregator
)
Expand All @@ -434,7 +436,7 @@ def run_model(self, is_weekday):


costs = costs_aggregator.get_costs_by_od_and_mode(
["cost", "distance", "time", "ghg_emissions"],
["distance", "time", "ghg_emissions", "cost"],
congestion=True
)

Expand Down Expand Up @@ -539,7 +541,7 @@ def evaluate(self, metric, **kwargs):
return evaluation


def plot_modal_share(self, zone="origin", mode="car", period="weekdays",
def plot_modal_share(self, zone="origin", mode="car", period="weekdays", plot=True,
labels=None, labels_size=[10, 6, 4], labels_color="black"):
"""
Plot modal share for the given mode in the origin or destination zones during weekdays or weekends.
Expand All @@ -560,7 +562,6 @@ def plot_modal_share(self, zone="origin", mode="car", period="weekdays",
Mode share for the given mode in each transport zone.

"""
logging.info(f"🗺️ Plotting {mode} modal share for {zone} zones during {period}")

if period == "weekdays":
population_df = self.get()["weekday_flows"].collect().to_pandas()
Expand Down Expand Up @@ -588,24 +589,27 @@ def plot_modal_share(self, zone="origin", mode="car", period="weekdays",
mode_name = mode.capitalize()
mode_share = mode_share[mode_share["mode"] == mode]

transport_zones_df = self.population.transport_zones.get()

gc = gpd.GeoDataFrame(
transport_zones_df.merge(mode_share, how="left", right_on=left_column, left_on="transport_zone_id", suffixes=('', '_z'))).fillna(0)
gcp = gc.plot("modal_share", legend=True)
gcp.set_axis_off()
plt.title(f"{mode_name} share per {zone} transport zone ({period})")
if plot:
logging.info(f"🗺️ Plotting {mode} modal share for {zone} zones during {period}")

if isinstance(labels, gpd.GeoDataFrame):
self.__show_labels__(labels, labels_size, labels_color)

plt.show()
transport_zones_df = self.population.transport_zones.get()

gc = gpd.GeoDataFrame(
transport_zones_df.merge(mode_share, how="left", right_on=left_column, left_on="transport_zone_id", suffixes=('', '_z'))).fillna(0)
gcp = gc.plot("modal_share", legend=True)
gcp.set_axis_off()
plt.title(f"{mode_name} share per {zone} transport zone ({period})")

if isinstance(labels, gpd.GeoDataFrame):
self.__show_labels__(labels, labels_size, labels_color)

plt.show()

return mode_share

def plot_od_flows(self, mode="all", motive="all", period="weekdays", level_of_detail=1,
n_largest=2000, color="blue", transparency=0.2, zones_color="xkcd:light grey",
labels=None, labels_size=[10, 6, 4], labels_color="black"):
labels=None, labels_size=[10, 6, 4], labels_color="black", save=False):
"""
Plot flows between the different zones for the given mode, motive, period and level of detail.

Expand Down Expand Up @@ -685,8 +689,8 @@ def plot_od_flows(self, mode="all", motive="all", period="weekdays", level_of_de
# Put a legend for width on bottom right, title on the top
x_min = float(biggest_flows[["x"]].min().iloc[0])
y_min = float(biggest_flows[["y"]].min().iloc[0])
plt.plot([x_min, x_min+4000], [y_min, y_min], linewidth=2, color=color)
plt.text(x_min+6000, y_min-1000, "1 000", color=color)
plt.plot([x_min-10000, x_min-8000], [y_min-2000, y_min-2000], linewidth=2, color=color)
plt.text(x_min-6000, y_min-3000, "1 000", color=color)
plt.title(f"{mode_name} flows between transport zones on {period}")

# Draw all origin-destinations
Expand All @@ -696,6 +700,10 @@ def plot_od_flows(self, mode="all", motive="all", period="weekdays", level_of_de

if isinstance(labels, gpd.GeoDataFrame):
self.__show_labels__(labels, labels_size, labels_color)

if save:
text = "plot-" + str(self.parameters["seed"]) + ".png"
plt.savefig(text)

plt.show()

Expand Down Expand Up @@ -757,13 +765,14 @@ def get_prominent_cities(self, n_cities=20, n_levels=3, distance_km=2):

# If an admin unit is too close to a bigger admin unit, make it less prominent
for i in range(n_cities//2):
coords = flows_per_commune.loc[i, "geometry"]
geoflows["dists"] = geoflows["geometry"].distance(coords)
# Use distance_km here
geoflows.loc[
((geoflows["dists"] < distance_km*1000) & (geoflows.index > i)), "prominence"
] = geoflows["prominence"] + 2
geoflows = geoflows.sort_values(by="prominence").reset_index(drop=True)
if i < len(flows_per_commune):
coords = flows_per_commune.loc[i, "geometry"]
geoflows["dists"] = geoflows["geometry"].distance(coords)
# Use distance_km here
geoflows.loc[
((geoflows["dists"] < distance_km*1000) & (geoflows.index > i)), "prominence"
] = geoflows["prominence"] + 2
geoflows = geoflows.sort_values(by="prominence").reset_index(drop=True)

# Keep only the most prominent admin units and add their centroids
geoflows = geoflows[geoflows["prominence"] <= n_levels]
Expand Down
Loading
Loading