Module gtfs_segments.geom_utils

Expand source code
import utm
import numpy as np
import geopandas as gpd
from shapely.ops import split
from shapely.geometry import Point
from scipy.spatial import cKDTree
import contextily as cx
import matplotlib.pyplot as plt

def split_route(row):
    """
    It takes a row from a dataframe, and if the row has a start and end point, it splits the route into
    two segments
    
    Args:
      row: row in stop_df
    
    Returns:
      the geometry of the route segments.
    """
    route= row['geometry']
    if row['snapped_start_id']:
        try:
            route = split(route,row['start']).geoms[1]
        except:
            route = route
    if row['snapped_end_id']:
        route = split(route,row['end']).geoms[0]
    return route.wkt

def nearest_snap(route,point):
    """
    It takes a dataframe of bus stops and a dataframe of bus routes and returns a dataframe of the
    nearest bus stop to each bus stop
    
    Args:
      route: the route id of the route you want to view
      point: the point you want to snap to the nearest point on the route
    
    Returns:
      a list of tuples. Each tuple contains the route_id, segment_id, and the distance between the two
    stops.
    """
    route = np.array(route.coords)
    point = np.array(point.coords)
    ckd_tree = cKDTree(route)
    return Point(route[ckd_tree.query(point, k=1)[1]][0]).wkt

def make_gdf(df):
    """
    It takes a dataframe and returns a geodataframe
    
    Args:
      df: the dataframe you want to convert to a geodataframe
    
    Returns:
      A GeoDataFrame
    """
    df = gpd.GeoDataFrame(df)
    df =  df.set_crs(epsg=4326,allow_override= True)
    return df

def code(zone,lat):
    """
    If the latitude is negative, the EPSG code is 32700 + the zone number. If the latitude is positive,
    the EPSG code is 32600 + the zone number
    
    Args:
      zone: The UTM zone number.
      lat: latitude of the point
    
    Returns:
      The EPSG code is 32600+zone for positive latitudes and 32700+zone for negatives.
    """
    #The EPSG code is 32600+zone for positive latitudes and 32700+zone for negatives.
    if lat <0:
        epsg_code = 32700 + zone[2]
    else:
        epsg_code = 32600 + zone[2]
    return epsg_code

def get_zone_epsg(stop_df):
    """
    > The function takes a dataframe with a geometry column and returns the EPSG code for the UTM zone
    that contains the geometry
    
    Args:
      stop_df: a dataframe with a geometry column
    
    Returns:
      The EPSG code for the UTM zone that the stop is in.
    """
    lon = stop_df.start[0].x
    lat = stop_df.start[0].y
    zone = utm.from_latlon(lat, lon)
    return code(zone,lat)

def view_spacings(df,basemap=False,level = "whole", axis ='on' ,**kwargs):
    """
    > This function plots the spacings of the bus network, or a specific route, or a specific segment
    
    Args:
      df: the dataframe containing the bus network
      basemap: if True, will add a basemap to the plot. Defaults to False
      level: "whole" or "route" or "segment". Defaults to whole
      axis: 'on' or 'off'. Defaults to on
    """
    fig,ax = plt.subplots(figsize = (8,6),dpi = 200)
    if level == "whole": 
        ax = df.plot(ax = ax,color='black',label='Bus network')
    if "route" in kwargs.keys():
        ax = df[df.route_id == kwargs['route']].plot(ax =ax, color = 'blue', label = kwargs['route'])
    if "segment" in kwargs.keys():
        ax = df[df.segment_id == kwargs['segment']].plot(ax =ax, color = 'brown', label = kwargs['segment'])
    if basemap:
        cx.add_basemap(ax,crs=df.crs)
    plt.axis(axis)
    plt.legend()
    plt.show()

Functions

def code(zone, lat)

If the latitude is negative, the EPSG code is 32700 + the zone number. If the latitude is positive, the EPSG code is 32600 + the zone number

Args

zone
The UTM zone number.
lat
latitude of the point

Returns

The EPSG code is 32600+zone for positive latitudes and 32700+zone for negatives.

Expand source code
def code(zone,lat):
    """
    If the latitude is negative, the EPSG code is 32700 + the zone number. If the latitude is positive,
    the EPSG code is 32600 + the zone number
    
    Args:
      zone: The UTM zone number.
      lat: latitude of the point
    
    Returns:
      The EPSG code is 32600+zone for positive latitudes and 32700+zone for negatives.
    """
    #The EPSG code is 32600+zone for positive latitudes and 32700+zone for negatives.
    if lat <0:
        epsg_code = 32700 + zone[2]
    else:
        epsg_code = 32600 + zone[2]
    return epsg_code
def get_zone_epsg(stop_df)

The function takes a dataframe with a geometry column and returns the EPSG code for the UTM zone that contains the geometry

Args

stop_df
a dataframe with a geometry column

Returns

The EPSG code for the UTM zone that the stop is in.

Expand source code
def get_zone_epsg(stop_df):
    """
    > The function takes a dataframe with a geometry column and returns the EPSG code for the UTM zone
    that contains the geometry
    
    Args:
      stop_df: a dataframe with a geometry column
    
    Returns:
      The EPSG code for the UTM zone that the stop is in.
    """
    lon = stop_df.start[0].x
    lat = stop_df.start[0].y
    zone = utm.from_latlon(lat, lon)
    return code(zone,lat)
def make_gdf(df)

It takes a dataframe and returns a geodataframe

Args

df
the dataframe you want to convert to a geodataframe

Returns

A GeoDataFrame

Expand source code
def make_gdf(df):
    """
    It takes a dataframe and returns a geodataframe
    
    Args:
      df: the dataframe you want to convert to a geodataframe
    
    Returns:
      A GeoDataFrame
    """
    df = gpd.GeoDataFrame(df)
    df =  df.set_crs(epsg=4326,allow_override= True)
    return df
def nearest_snap(route, point)

It takes a dataframe of bus stops and a dataframe of bus routes and returns a dataframe of the nearest bus stop to each bus stop

Args

route
the route id of the route you want to view
point
the point you want to snap to the nearest point on the route

Returns

a list of tuples. Each tuple contains the route_id, segment_id, and the distance between the two stops.

Expand source code
def nearest_snap(route,point):
    """
    It takes a dataframe of bus stops and a dataframe of bus routes and returns a dataframe of the
    nearest bus stop to each bus stop
    
    Args:
      route: the route id of the route you want to view
      point: the point you want to snap to the nearest point on the route
    
    Returns:
      a list of tuples. Each tuple contains the route_id, segment_id, and the distance between the two
    stops.
    """
    route = np.array(route.coords)
    point = np.array(point.coords)
    ckd_tree = cKDTree(route)
    return Point(route[ckd_tree.query(point, k=1)[1]][0]).wkt
def split_route(row)

It takes a row from a dataframe, and if the row has a start and end point, it splits the route into two segments

Args

row
row in stop_df

Returns

the geometry of the route segments.

Expand source code
def split_route(row):
    """
    It takes a row from a dataframe, and if the row has a start and end point, it splits the route into
    two segments
    
    Args:
      row: row in stop_df
    
    Returns:
      the geometry of the route segments.
    """
    route= row['geometry']
    if row['snapped_start_id']:
        try:
            route = split(route,row['start']).geoms[1]
        except:
            route = route
    if row['snapped_end_id']:
        route = split(route,row['end']).geoms[0]
    return route.wkt
def view_spacings(df, basemap=False, level='whole', axis='on', **kwargs)

This function plots the spacings of the bus network, or a specific route, or a specific segment

Args

df
the dataframe containing the bus network
basemap
if True, will add a basemap to the plot. Defaults to False
level
"whole" or "route" or "segment". Defaults to whole
axis
'on' or 'off'. Defaults to on
Expand source code
def view_spacings(df,basemap=False,level = "whole", axis ='on' ,**kwargs):
    """
    > This function plots the spacings of the bus network, or a specific route, or a specific segment
    
    Args:
      df: the dataframe containing the bus network
      basemap: if True, will add a basemap to the plot. Defaults to False
      level: "whole" or "route" or "segment". Defaults to whole
      axis: 'on' or 'off'. Defaults to on
    """
    fig,ax = plt.subplots(figsize = (8,6),dpi = 200)
    if level == "whole": 
        ax = df.plot(ax = ax,color='black',label='Bus network')
    if "route" in kwargs.keys():
        ax = df[df.route_id == kwargs['route']].plot(ax =ax, color = 'blue', label = kwargs['route'])
    if "segment" in kwargs.keys():
        ax = df[df.segment_id == kwargs['segment']].plot(ax =ax, color = 'brown', label = kwargs['segment'])
    if basemap:
        cx.add_basemap(ax,crs=df.crs)
    plt.axis(axis)
    plt.legend()
    plt.show()