Skip to content

Filtering

FeedFilteringMixin

Mixin providing Feed.filter_by_date_range/filter_by_date/filter_by_time_range/filter_by_route_type/filter and the calendar_new_start_date/calendar_new_end_date helpers.

filter_by_date_range

filter_by_date_range(start_date: datetime | date | None = None, end_date: datetime | date | None = None, date_type: str | list[str] | None = None) -> pl.LazyFrame

Filters a LazyFrame based on a date range.

It uses the Calendar object to find all service_ids active within the specified date range and then semi-joins the input data with these service IDs.

Parameters:

Name Type Description Default
start_date datetime

The start of the date range (inclusive).

None
end_date datetime

The end of the date range (inclusive).

None

Returns:

Type Description
LazyFrame

pl.LazyFrame: The filtered LazyFrame.

Source code in pyGTFSHandler/analysis/filtering.py
def filter_by_date_range(
    self,
    start_date: datetime | date | None = None,
    end_date: datetime | date | None = None,
    date_type: str | list[str] | None = None,
) -> pl.LazyFrame:
    """
    Filters a LazyFrame based on a date range.

    It uses the `Calendar` object to find all `service_id`s active within
    the specified date range and then semi-joins the input data with these
    service IDs.

    Args:
        start_date (datetime): The start of the date range (inclusive).
        end_date (datetime): The end of the date range (inclusive).

    Returns:
        pl.LazyFrame: The filtered LazyFrame.
    """
    return self._filter_by_date_range(self.lf,start_date,end_date,date_type)

filter_by_date

filter_by_date(date: datetime | date) -> pl.LazyFrame

Filters a LazyFrame based on a date.

It uses the Calendar object to find all service_ids active within the specified date range and then semi-joins the input data with these service IDs.

Parameters:

Name Type Description Default
date datetime

The desired date.

required

Returns:

Type Description
LazyFrame

pl.LazyFrame: The filtered LazyFrame.

Source code in pyGTFSHandler/analysis/filtering.py
def filter_by_date(
    self,
    date: datetime | date,
) -> pl.LazyFrame:
    """
    Filters a LazyFrame based on a date.

    It uses the `Calendar` object to find all `service_id`s active within
    the specified date range and then semi-joins the input data with these
    service IDs.

    Args:
        date (datetime): The desired date.

    Returns:
        pl.LazyFrame: The filtered LazyFrame.
    """

    return self._filter_by_date(self.lf,date)

filter_by_time_range

filter_by_time_range(start_time: datetime | time = time(hour=0), end_time: datetime | time = time(hour=23, minute=59, second=59)) -> pl.LazyFrame

Filters a LazyFrame based on a time-of-day range.

It handles trips defined by frequencies.txt differently from those with explicit schedules.

Parameters:

Name Type Description Default
start_time datetime

The start of the time range. Defaults to 00:00:00.

time(hour=0)
end_time datetime

The end of the time range. Defaults to 23:59:59.

time(hour=23, minute=59, second=59)

Returns:

Type Description
LazyFrame

pl.LazyFrame: The filtered LazyFrame.

Source code in pyGTFSHandler/analysis/filtering.py
def filter_by_time_range(
    self,
    start_time: datetime | time = time(hour=0),
    end_time: datetime | time = time(hour=23, minute=59, second=59),
) -> pl.LazyFrame:
    """
    Filters a LazyFrame based on a time-of-day range.

    It handles trips defined by `frequencies.txt` differently from those with
    explicit schedules.

    Args:
        start_time (datetime): The start of the time range. Defaults to 00:00:00.
        end_time (datetime): The end of the time range. Defaults to 23:59:59.

    Returns:
        pl.LazyFrame: The filtered LazyFrame.
    """
    return self._filter_by_time_range(self.lf,start_time,end_time)

filter_by_route_type

filter_by_route_type(route_types: list | int | str) -> pl.LazyFrame

Filters self.lf down to rows whose route_type matches route_types.

Parameters:

Name Type Description Default
route_types list | int | str

One or more route type names (e.g. "bus") or GTFS route type codes (e.g. 3), normalized the same way as the route_types argument of Feed's constructor.

required

Returns:

Type Description
LazyFrame

pl.LazyFrame: self.lf filtered to the requested route types.

Source code in pyGTFSHandler/analysis/filtering.py
def filter_by_route_type(
    self, route_types: list | int | str
) -> pl.LazyFrame:
    """Filters `self.lf` down to rows whose `route_type` matches `route_types`.

    Args:
        route_types: One or more route type names (e.g. `"bus"`) or
            GTFS route type codes (e.g. `3`), normalized the same way
            as the `route_types` argument of `Feed`'s constructor.

    Returns:
        pl.LazyFrame: `self.lf` filtered to the requested route types.
    """
    return self._filter_by_route_type(self.lf,route_types)

filter

filter(start_date: datetime | date | None = None, end_date: datetime | date | None = None, date: datetime | date | None = None, date_type: str | list[str] | None = None, start_time: datetime | time = time(hour=0), end_time: datetime | time = time(hour=23, minute=59, second=59), route_types: list | int | str | None = None, frequencies: bool = True, in_aoi: bool = False, delete_last_stop: bool = False) -> pl.LazyFrame

Filters the integrated feed LazyFrame (self.lf) by date/time/route/AOI.

Central helper used by most Feed analysis methods (get_headway_at_stops, get_headway_at_edges, etc.) to narrow self.lf down to a single service window before aggregating.

Parameters:

Name Type Description Default
start_date datetime | date | None

Inclusive start of a date range filter. Ignored if date is given.

None
end_date datetime | date | None

Inclusive end of a date range filter. Ignored if date is given.

None
date datetime | date | None

A single service date; takes precedence over start_date/end_date when given.

None
date_type str | list[str] | None

Optional weekday/weekend/holiday classification filter (see Calendar.filter_by_date_type).

None
start_time datetime | time

Start of the daily time window.

time(hour=0)
end_time datetime | time

End of the daily time window.

time(hour=23, minute=59, second=59)
route_types list | int | str | None

Optional route type filter.

None
frequencies bool

If True (default), frequencies.txt-defined trips are left as unexpanded templates. If False, they are expanded into concrete, individually addressable departures (via _frequencies_to_stop_times) before filtering.

True
in_aoi bool

If True, restrict to stops flagged isin_aoi.

False
delete_last_stop bool

If True, drop each trip's final stop (useful when computing edge-based, not stop-based, metrics).

False

Returns:

Type Description
LazyFrame

pl.LazyFrame: The filtered LazyFrame.

Source code in pyGTFSHandler/analysis/filtering.py
def filter(
        self,
        start_date: datetime | date | None = None,
        end_date: datetime | date | None = None,
        date: datetime | date | None = None,
        date_type: str | list[str] | None = None,
        start_time: datetime | time = time(hour=0),
        end_time: datetime | time = time(hour=23, minute=59, second=59),
        route_types: list | int | str | None = None,
        frequencies:bool = True,
        in_aoi:bool = False,
        delete_last_stop:bool = False
    ) -> pl.LazyFrame:
    """Filters the integrated feed LazyFrame (`self.lf`) by date/time/route/AOI.

    Central helper used by most `Feed` analysis methods
    (`get_headway_at_stops`, `get_headway_at_edges`, etc.) to narrow
    `self.lf` down to a single service window before aggregating.

    Args:
        start_date: Inclusive start of a date range filter. Ignored if
            `date` is given.
        end_date: Inclusive end of a date range filter. Ignored if
            `date` is given.
        date: A single service date; takes precedence over
            `start_date`/`end_date` when given.
        date_type: Optional weekday/weekend/holiday classification
            filter (see `Calendar.filter_by_date_type`).
        start_time: Start of the daily time window.
        end_time: End of the daily time window.
        route_types: Optional route type filter.
        frequencies: If `True` (default), `frequencies.txt`-defined
            trips are left as unexpanded templates. If `False`, they are
            expanded into concrete, individually addressable departures
            (via `_frequencies_to_stop_times`) before filtering.
        in_aoi: If `True`, restrict to stops flagged `isin_aoi`.
        delete_last_stop: If `True`, drop each trip's final stop (useful
            when computing edge-based, not stop-based, metrics).

    Returns:
        pl.LazyFrame: The filtered LazyFrame.
    """
    lf = self.lf
    return self._filter(
        lf,
        start_date,
        end_date,
        date,
        date_type,
        start_time,
        end_time,
        route_types,
        frequencies,
        in_aoi,
        delete_last_stop
    ) 

calendar_new_end_date

calendar_new_end_date(new_end_date: datetime | date, file_id: int | None = None, gtfs_name: str | None = None)

Overwrites end_date in self.calendar.lf (calendar.txt rows), in place.

Useful for extending/truncating a feed's validity window (e.g. before combining several historical feeds) without re-loading from disk.

Parameters:

Name Type Description Default
new_end_date datetime | date

Replacement end date.

required
file_id int | None

If given, only rows loaded from this source file index are updated.

None
gtfs_name str | None

If given (and file_id is not), only rows whose gtfs_name matches are updated. If neither is given, every row's end_date is overwritten.

None
Source code in pyGTFSHandler/analysis/filtering.py
def calendar_new_end_date(self, new_end_date: datetime | date, file_id: int | None = None, gtfs_name: str | None = None):
    """Overwrites `end_date` in `self.calendar.lf` (calendar.txt rows), in place.

    Useful for extending/truncating a feed's validity window (e.g.
    before combining several historical feeds) without re-loading from
    disk.

    Args:
        new_end_date: Replacement end date.
        file_id: If given, only rows loaded from this source file index
            are updated.
        gtfs_name: If given (and `file_id` is not), only rows whose
            `gtfs_name` matches are updated. If neither is given, every
            row's `end_date` is overwritten.
    """
    end_date = int(date_parsing.datetime_to_days_since_epoch(new_end_date))
    if self.calendar.lf is not None:
        if file_id is not None:
            self.calendar.lf = self.calendar.lf.with_columns(
                pl.when(
                    pl.col("file_id") == pl.lit(file_id)
                ).then(
                pl.lit(end_date)
                ).otherwise(pl.col("end_date")
                ).alias("end_date")
            )
        elif gtfs_name is not None:
            self.calendar.lf = self.calendar.lf.with_columns(
                pl.when(
                    pl.col("gtfs_name") == pl.lit(gtfs_name)
                ).then(
                pl.lit(end_date)
                ).otherwise(pl.col("end_date")
                ).alias("end_date")
            )
        else:
            self.calendar.lf = self.calendar.lf.with_columns(
                pl.lit(end_date).alias("end_date")
            )

calendar_new_start_date

calendar_new_start_date(new_start_date: datetime | date, file_id: int | None = None, gtfs_name: str | None = None)

Overwrites start_date in self.calendar.lf (calendar.txt rows), in place.

Mirror of calendar_new_end_date for the start of the validity window; see that method for the file_id/gtfs_name selection semantics.

Parameters:

Name Type Description Default
new_start_date datetime | date

Replacement start date.

required
file_id int | None

If given, only rows loaded from this source file index are updated.

None
gtfs_name str | None

If given (and file_id is not), only rows whose gtfs_name matches are updated. If neither is given, every row's start_date is overwritten.

None
Source code in pyGTFSHandler/analysis/filtering.py
def calendar_new_start_date(self, new_start_date: datetime | date, file_id: int | None = None, gtfs_name: str | None = None):
    """Overwrites `start_date` in `self.calendar.lf` (calendar.txt rows), in place.

    Mirror of `calendar_new_end_date` for the start of the validity
    window; see that method for the `file_id`/`gtfs_name` selection
    semantics.

    Args:
        new_start_date: Replacement start date.
        file_id: If given, only rows loaded from this source file index
            are updated.
        gtfs_name: If given (and `file_id` is not), only rows whose
            `gtfs_name` matches are updated. If neither is given, every
            row's `start_date` is overwritten.
    """
    start_date = int(date_parsing.datetime_to_days_since_epoch(new_start_date))
    if self.calendar.lf is not None:
        if file_id is not None:
            self.calendar.lf = self.calendar.lf.with_columns(
                pl.when(
                    pl.col("file_id") == pl.lit(file_id)
                ).then(
                pl.lit(start_date)
                ).otherwise(pl.col("start_date")
                ).alias("start_date")
            )
        elif gtfs_name is not None:
            self.calendar.lf = self.calendar.lf.with_columns(
                pl.when(
                    pl.col("gtfs_name") == pl.lit(gtfs_name)
                ).then(
                pl.lit(start_date)
                ).otherwise(pl.col("start_date")
                ).alias("start_date")
            )
        else:
            self.calendar.lf = self.calendar.lf.with_columns(
                pl.lit(start_date).alias("start_date")
            )

See also Edge & filtering methodology.