import pandas as pd
import hillmaker as hm
Analyzing bike usage by time of day and day of week
Using hillmaker for occupancy analysis of cycle share data
python
hillmaker
occupancy analysis
pandas
matplotlib
bikeshare
The bike use plots
Four different plots are created using matplotlib
to explore time of day and day of week patterns in bike users by different user types.
# Create a Figure and Axes object
#--------------------------------
= plt.figure()
fig1 = fig1.add_subplot(1,1,1)
ax1
# Create a list to use as the X-axis values
#-------------------------------------------
= pd.date_range('01/05/2015', periods=168, freq='60Min').tolist()
timestamps
= pd.date_range('01/05/2015 12:00:00', periods=7, freq='24H').tolist()
major_tick_locations = pd.date_range('01/05/2015 06:00:00', periods=28, freq='6H').tolist()
minor_tick_locations
# Specify the mean occupancy and percentile values
#-----------------------------------------------------------
= total_df['mean']
mean_occ = total_df['p95']
pctile_occ
# Styling of bars, lines, plot area
#-----------------------------------
# Style the bars for mean occupancy
= 'grey'
bar_color = 0.8
bar_opacity
# Style the line for the occupancy percentile
= '-'
pctile_line_style = 'black'
pctile_color = 1
pctile_line_width
# Set the background color of the plot. Argument is a string float in
# (0,1) representing greyscale (0=black, 1=white)
'0.95')
ax1.patch.set_facecolor(
# Can also use color names or hex color codes
# ax2.patch.set_facecolor('yellow')
# ax2.patch.set_facecolor('#FFFFAD')
# Add data to the plot
#--------------------------
# Mean occupancy as bars - here's the GOTCHA involving the bar width
=bar_color, alpha=bar_opacity, label='Mean # bikes in use', width=1/24)
ax1.bar(timestamps, mean_occ, color
# Some percentile as a line
=pctile_line_style, linewidth=pctile_line_width, color=pctile_color, \
ax1.plot(timestamps, pctile_occ, linestyle='95th %ile # bikes in use')
label
# Create formatter variables
= DateFormatter('%a')
dayofweek_formatter = DateFormatter('%H')
qtrday_formatter
# Set the tick locations for the axes object
ax1.set_xticks(major_tick_locations)=True)
ax1.set_xticks(minor_tick_locations, minor
# Format the tick labels
ax1.xaxis.set_major_formatter(dayofweek_formatter)
ax1.xaxis.set_minor_formatter(qtrday_formatter)
# Slide the major tick labels underneath the default location by 20 points
='major', pad=20)
ax1.tick_params(which
# Add other chart elements
#-------------------------
# Set plot and axis titles
'Bike Usage by Time of Day and Day of Week', fontsize=28, fontweight='bold')
fig1.suptitle('All user types', fontsize=24)
ax1.set_title('Time Bin of Week', fontsize=14)
ax1.set_xlabel('# Bikes in use', fontsize=14)
ax1.set_ylabel(
# Gridlines
True, color='k')
ax1.grid(
# Legend
= ax1.legend(loc='best', frameon=True, fontsize=20)
leg 'white')
leg.get_frame().set_facecolor(
# Plot size
16,12) fig1.set_size_inches(
Weekdays only and weekends only
Now we’ll create separate plots for weekdays and weekends and we’ll stack the bars based on user type.
# Gather various series to use in the plots
= occ_df.loc['Short-Term Pass Holder']
shortterm_df = occ_df.loc['Member']
member_df
# Remember that weekdays are number 0 to 6 in Python with 0=Monday
= shortterm_df.loc[0:4]['mean']
wkday_mean_shortterm_occ = member_df.loc[0:4]['mean']
wkday_mean_member_occ = total_df.loc[0:4]['p95']
wkday_p95_total_occ = total_df.loc[0:4]['p80']
wkday_p80_total_occ
= shortterm_df.loc[5:6]['mean']
wkend_mean_shortterm_occ = member_df.loc[5:6]['mean']
wkend_mean_member_occ = total_df.loc[5:6]['p95']
wkend_p95_total_occ = total_df.loc[5:6]['p80'] wkend_p80_total_occ
# Create a Figure and Axes object
#--------------------------------
= plt.figure()
fig2 = fig2.add_subplot(1,1,1)
ax2
# Create a list to use as the X-axis values
#-------------------------------------------
= pd.date_range('01/05/2015', periods=120, freq='60Min').tolist()
timestamps
= pd.date_range('01/05/2015 12:00:00', periods=5, freq='24H').tolist()
major_tick_locations = pd.date_range('01/05/2015 06:00:00', periods=20, freq='6H').tolist()
minor_tick_locations
# Styling of bars, lines, plot area
#-----------------------------------
# Style the bars for mean occupancy
= 'grey'
bar_color_member = 'green'
bar_color_shortterm = 0.8
bar_opacity
# Style the line for the occupancy percentile
= '-'
pctile95_line_style = '--'
pctile80_line_style = 'black'
pctile_color = 0.75
pctile_line_width
# Set the background color of the plot. Argument is a string float in
# (0,1) representing greyscale (0=black, 1=white)
'0.95')
ax2.patch.set_facecolor(
# Can also use color names or hex color codes
# ax2.patch.set_facecolor('yellow')
# ax2.patch.set_facecolor('#FFFFAD')
# Add data to the plot
#--------------------------
= 'Mean # bikes in use - Members'
label_member = 'Mean # bikes in use - Short-Term Pass'
label_shortterm
# Mean occupancy as bars
=bar_color_member, alpha=bar_opacity, label=label_member, width=1/24)
ax2.bar(timestamps, wkday_mean_member_occ, color=wkday_mean_member_occ, color=bar_color_shortterm,
ax2.bar(timestamps, wkday_mean_shortterm_occ, bottom=bar_opacity, label=label_shortterm, width=1/24)
alpha
# Percentiles as lines
=pctile95_line_style, linewidth=pctile_line_width, color=pctile_color, \
ax2.plot(timestamps, wkday_p95_total_occ, linestyle='95th %ile # bikes in use')
label
=pctile80_line_style, linewidth=pctile_line_width, color=pctile_color, \
ax2.plot(timestamps, wkday_p80_total_occ, linestyle='80th %ile # bikes in use')
label
# Create formatter variables
= DateFormatter('%a')
dayofweek_formatter = DateFormatter('%H')
qtrday_formatter
# Set the tick locations for the axes object
ax2.set_xticks(major_tick_locations)=True)
ax2.set_xticks(minor_tick_locations, minor
# Format the tick labels
ax2.xaxis.set_major_formatter(dayofweek_formatter)
ax2.xaxis.set_minor_formatter(qtrday_formatter)
# Slide the major tick labels underneath the default location by 20 points
='major', pad=20)
ax2.tick_params(which
# Add other chart elements
#-------------------------
# Set plot and axis titles
'Bike Usage by Time of Day - Weekdays', fontsize=16)
ax2.set_title('Time Bin of Week', fontsize=14)
ax2.set_xlabel('# Bikes in use', fontsize=14)
ax2.set_ylabel(
# Gridlines
True, color='grey')
ax2.grid(
# Legend
= ax2.legend(loc='best', frameon=True, fontsize=10)
leg 'white')
leg.get_frame().set_facecolor(
# Plot size
8,6) fig2.set_size_inches(
# Create a Figure and Axes object
#--------------------------------
= plt.figure()
fig3 = fig3.add_subplot(1,1,1)
ax3
# Create a list to use as the X-axis values
#-------------------------------------------
= pd.date_range('01/03/2015', periods=48, freq='60Min').tolist()
timestamps
= pd.date_range('01/03/2015 12:00:00', periods=2, freq='24H').tolist()
major_tick_locations = pd.date_range('01/03/2015 06:00:00', periods=8, freq='6H').tolist()
minor_tick_locations
# Styling of bars, lines, plot area
#-----------------------------------
# Style the bars for mean occupancy
= 'grey'
bar_color_member = 'green'
bar_color_shortterm = 0.8
bar_opacity
# Style the line for the occupancy percentile
= '-'
pctile_line_style = 'black'
pctile_color = 1
pctile_line_width
# Set the background color of the plot. Argument is a string float in
# (0,1) representing greyscale (0=black, 1=white)
'0.95')
ax3.patch.set_facecolor(
# Can also use color names or hex color codes
# ax2.patch.set_facecolor('yellow')
# ax2.patch.set_facecolor('#FFFFAD')
# Add data to the plot
#--------------------------
= 'Mean # bikes in use - Members'
label_member = 'Mean # bikes in use - Short-Term Pass'
label_shortterm
# Mean occupancy as bars
=bar_color_member, alpha=bar_opacity, label=label_member, width=1/24)
ax3.bar(timestamps, wkend_mean_member_occ, color=wkend_mean_member_occ, color=bar_color_shortterm,
ax3.bar(timestamps, wkend_mean_shortterm_occ, bottom=bar_opacity, label=label_shortterm, width=1/24)
alpha
# Some percentile aas a line
=pctile_line_style, linewidth=pctile_line_width, color=pctile_color, \
ax3.plot(timestamps, wkend_p95_total_occ, linestyle='95th %ile # bikes in use')
label
# Create formatter variables
= DateFormatter('%a')
dayofweek_formatter = DateFormatter('%H')
qtrday_formatter
# Set the tick locations for the axes object
ax3.set_xticks(major_tick_locations)=True)
ax3.set_xticks(minor_tick_locations, minor
# Format the tick labels
ax3.xaxis.set_major_formatter(dayofweek_formatter)
ax3.xaxis.set_minor_formatter(qtrday_formatter)
# Slide the major tick labels underneath the default location by 20 points
='major', pad=20)
ax3.tick_params(which
# Add other chart elements
#-------------------------
# Set plot and axis titles
'Bikes Usage by Time of Day - Weekends', fontsize=16)
ax3.set_title('Time Bin of Week', fontsize=14)
ax3.set_xlabel('# Bikes in use', fontsize=14)
ax3.set_ylabel(
# Gridlines
True, color='k')
ax3.grid(
# Legend
= ax3.legend(loc='upper right', frameon=True, fontsize=10)
leg 'white')
leg.get_frame().set_facecolor(
# Plot size
8,6) fig3.set_size_inches(
# Create a Figure and Axes object
#--------------------------------
= plt.figure()
fig4 = fig4.add_subplot(1,1,1)
ax4
# Create a list to use as the X-axis values
#-------------------------------------------
= pd.date_range('01/05/2015', periods=168, freq='60Min').tolist()
timestamps
= pd.date_range('01/05/2015 12:00:00', periods=7, freq='24H').tolist()
major_tick_locations = pd.date_range('01/05/2015 06:00:00', periods=28, freq='6H').tolist()
minor_tick_locations
# Specify the mean occupancy and percentile values
#-----------------------------------------------------------
= occ_df.loc['Short-Term Pass Holder']['mean']
mean_shortterm_occ = occ_df.loc['Member']['mean']
mean_member_occ = occ_df.loc['Total']['p95']
p95_total_occ
# Styling of bars, lines, plot area
#-----------------------------------
# Style the bars for mean occupancy
= 'grey'
bar_color_member = 'green'
bar_color_shortterm = 0.8
bar_opacity
# Style the line for the occupancy percentile
= '-'
pctile_line_style = 'black'
pctile_color = 1
pctile_line_width
# Set the background color of the plot. Argument is a string float in
# (0,1) representing greyscale (0=black, 1=white)
'0.95')
ax4.patch.set_facecolor(
# Can also use color names or hex color codes
# ax2.patch.set_facecolor('yellow')
# ax2.patch.set_facecolor('#FFFFAD')
# Add data to the plot
#--------------------------
= 'Mean # bikes in use - Members'
label_member = 'Mean # bikes in use - Short-Term Pass'
label_shortterm
# Mean occupancy as bars
=bar_color_member, alpha=bar_opacity, label=label_member, width=1/24)
ax4.bar(timestamps, mean_member_occ, color=mean_member_occ, color=bar_color_shortterm,
ax4.bar(timestamps, mean_shortterm_occ, bottom=bar_opacity, label=label_shortterm, width=1/24)
alpha
# Some percentile aas a line
=pctile_line_style, linewidth=pctile_line_width, color=pctile_color, \
ax4.plot(timestamps, p95_total_occ, linestyle='95th %ile total # bikes in use')
label
# Create formatter variables
= DateFormatter('%a')
dayofweek_formatter = DateFormatter('%H')
qtrday_formatter
# Set the tick locations for the axes object
ax4.set_xticks(major_tick_locations)=True)
ax4.set_xticks(minor_tick_locations, minor
# Format the tick labels
ax4.xaxis.set_major_formatter(dayofweek_formatter)
ax4.xaxis.set_minor_formatter(qtrday_formatter)
# Slide the major tick labels underneath the default location by 20 points
='major', pad=20)
ax4.tick_params(which
# Add other chart elements
#-------------------------
# Set plot and axis titles
'Bike Usage by Time of Day and Day of Week', fontsize=24, fontweight='bold')
fig4.suptitle('All user types', fontsize=20)
ax4.set_title('Time Bin of Week', fontsize=14)
ax4.set_xlabel('# Bikes in use', fontsize=14)
ax4.set_ylabel(
# Gridlines
True, color='k')
ax4.grid(
# Legend
= ax4.legend(loc='best', frameon=True, fontsize=16)
leg 'white')
leg.get_frame().set_facecolor(
# Plot size
12,9) fig4.set_size_inches(
Lots more we can do, but this should illustrate the basic idea.
Reuse
Citation
BibTeX citation:
@online{isken2019,
author = {Mark Isken},
title = {Analyzing Bike Usage by Time of Day and Day of Week},
date = {2019-01-01},
langid = {en}
}
For attribution, please cite this work as:
Mark Isken. 2019. “Analyzing Bike Usage by Time of Day and Day of
Week.” January 1, 2019.