It will be important to start tracking the number of scheduled trips starting from pre-COVID up to date. This will help to check whether the CTA decides to lower the number of scheduled trips to match the actual trips. The reduction in scheduled trips will improve the trip ratios, but the bus service will still be lower than pre-COVID levels, a less than ideal scenario.
Data
To access older data, you will need to look at schedule versions from transitfeeds.com dating back to 2019. You probably do not need to choose every schedule version for a given year because there is some overlap of the date ranges between the versions. It is good to check, however, that the schedule versions you choose span the entire year. For 2019, for example, you could choose the versions "7 November 2018" (6 November 2018 - 31 January 2019), "31 January 2019" (30 January 2019 - 31 March 2019), "14 April 2019" (29 March 2019 - 31 May 2019), "16 May 2019" (13 May 2019 - 31 July 2019), "5 August 2019" (1 August 2019 - 31 October 2019), "4 October 2019" (4 October 2019 - 31 December 2019). You could then drop the 2018 dates and duplicates that may arise from the overlapping dates.
Set up your virtual environment with the required packages by following the instructions in the README, and activate it. Once you have the schedule feeds of interest, run the snippet from inside the data_analysis directory. If running from the project root, change static_gtfs_analysis to data_analysis.static_gtfs_analysis.
from tqdm import tqdm
import pandas as pd
import logging
import static_gtfs_analysis
logger = logging.getLogger()
logging.basicConfig(level=logging.INFO)
def fetch_data_from_schedule(schedule_feeds: List[dict]) -> List[dict]:
"""Retrieve data from the GTFS file for various schedule versions.
Args:
schedule_feeds (List[dict]): A list of dictionaries containing
the version, start_date, and end_date as keys.
Returns:
List[dict]: A list of dictionaries with the schedule version and the
corresponding data.
"""
schedule_data_list = []
pbar = tqdm(schedule_feeds)
for feed in pbar:
schedule_version = feed["schedule_version"]
pbar.set_description(
f"Generating daily schedule data for "
f"schedule version {schedule_version}"
)
logging.info(
f"\nDownloading zip file for schedule version "
f"{schedule_version}"
)
CTA_GTFS = static_gtfs_analysis.download_zip(schedule_version)
logging.info("\nExtracting data")
data = static_gtfs_analysis.GTFSFeed.extract_data(
CTA_GTFS,
version_id=schedule_version
)
data = static_gtfs_analysis.format_dates_hours(data)
logging.info("\nSummarizing trip data")
trip_summary = static_gtfs_analysis.make_trip_summary(data)
route_daily_summary = (
static_gtfs_analysis
.summarize_date_rt(trip_summary)
)
schedule_data_list.append(
{"schedule_version": schedule_version,
"data": route_daily_summary}
)
return schedule_data_list
schedule_feeds = [
{
"schedule_version": "20181107",
"feed_start_date": "2018-11-06",
"feed_end_date": "2019-01-31"
},
# Enter remaining schedule versions of interest from 2019, 2020, and 2021
{
"schedule_version": "20220507",
"feed_start_date": "2022-05-20",
"feed_end_date": "2022-06-02",
},
{
"schedule_version": "20220603",
"feed_start_date": "2022-06-04",
"feed_end_date": "2022-06-07",
},
{
"schedule_version": "20220608",
"feed_start_date": "2022-06-09",
"feed_end_date": "2022-07-08",
},
{
"schedule_version": "20220709",
"feed_start_date": "2022-07-10",
"feed_end_date": "2022-07-17",
},
{
"schedule_version": "20220718",
"feed_start_date": "2022-07-19",
"feed_end_date": "2022-07-20",
},
]
schedule_data_list = fetch_data_from_schedule(schedule_feeds)
Access the schedule data in the list with
schedule_df = pd.concat([feed["data"] for feed in schedule_data_list])
schedule_df.drop_duplicates(inplace=True)
schedule_df should have enough information to generate plots of scheduled trip counts by day.
Example
schedule_feeds = [
{
"schedule_version": "20181107",
"feed_start_date": "2018-11-06",
"feed_end_date": "2019-01-31"
},
{
"schedule_version": "20190131",
"feed_start_date": "2019-01-30",
"feed_end_date": "2019-03-31"
}
]
schedule_data_list = fetch_data_from_schedule(schedule_feeds)
schedule_df = pd.concat([feed["data"] for feed in schedule_data_list])
print(schedule_df.duplicated().sum())
# 194 duplicates
schedule_df.drop_duplicates(inplace=True)
print(schedule_df.head())
# date route_id trip_count
# 0 2018-11-06 1 95
# 1 2018-11-06 100 73
# 2 2018-11-06 103 194
# 3 2018-11-06 106 169
# 4 2018-11-06 108 97
# Let's check the date ranges
print(f"The earliest date is {schedule_df.date.min()}")
print(f"The latest date is {schedule_df.date.max()}")
# The earliest date is 2018-11-06
# The latest date is 2019-03-31
# Drop the 2018 dates
schedule_df['date'] = pd.to_datetime(schedule_df["date"])
schedule_df_2019 = schedule_df.loc[schedule_df['date'].dt.year != 2018].copy()
# Print the date ranges again
print(f"The earliest date is {schedule_df_2019.date.min()}")
print(f"The latest date is {schedule_df_2019.date.max()}")
# The earliest date is 2019-01-01 00:00:00
# The latest date is 2019-03-31 00:00:00
It will be important to start tracking the number of scheduled trips starting from pre-COVID up to date. This will help to check whether the CTA decides to lower the number of scheduled trips to match the actual trips. The reduction in scheduled trips will improve the trip ratios, but the bus service will still be lower than pre-COVID levels, a less than ideal scenario.
Data
To access older data, you will need to look at schedule versions from transitfeeds.com dating back to 2019. You probably do not need to choose every schedule version for a given year because there is some overlap of the date ranges between the versions. It is good to check, however, that the schedule versions you choose span the entire year. For 2019, for example, you could choose the versions "7 November 2018" (6 November 2018 - 31 January 2019), "31 January 2019" (30 January 2019 - 31 March 2019), "14 April 2019" (29 March 2019 - 31 May 2019), "16 May 2019" (13 May 2019 - 31 July 2019), "5 August 2019" (1 August 2019 - 31 October 2019), "4 October 2019" (4 October 2019 - 31 December 2019). You could then drop the 2018 dates and duplicates that may arise from the overlapping dates.
Set up your virtual environment with the required packages by following the instructions in the README, and activate it. Once you have the schedule feeds of interest, run the snippet from inside the
data_analysisdirectory. If running from the project root, changestatic_gtfs_analysistodata_analysis.static_gtfs_analysis.Access the schedule data in the list with
schedule_dfshould have enough information to generate plots of scheduled trip counts by day.Example