import pandas as pd import numpy import plotly.plotly as py from plotly.graph_objs import * red_orange = '#FF3300' light_cyan = '#00CCFF' gray_light = '#bbbbbb' # takes very long time! df = pd.read_csv('raw_data/Baltimore_Parking_Citations_2015-03-06.csv',index_col='citation', parse_dates=[10], infer_datetime_format=True) df['violFine_parsed'] = df['violFine'].str.replace("$","").apply(lambda x: float(x)) df['openFine_parsed'] = df['openFine'].str.replace("$","").apply(lambda x: float(x)) df['openPenalty_parsed'] = df['openPenalty'].str.replace("$","").apply(lambda x: float(x)) df['balance_parsed'] = df['balance'].str.replace("$","").apply(lambda x: float(x)) len(df) df.head() groupby_desc = df.groupby('Description') citation_desc = pd.DataFrame() # Total fines for each citation type citation_desc['fines'] = groupby_desc['violFine_parsed'].sum() # Number of unique locations each citation type was issued at citation_desc['unique_locs'] = groupby_desc['location'].nunique() # Fine type concentration by location citation_desc['fine_conc_loc'] = (citation_desc['fines'] / citation_desc['unique_locs']).apply(lambda x: round(x,2)) citation_desc.sort('fines',inplace=True,ascending=False) citation_desc['first_date'] = '' citation_desc['last_date'] = '' for row in citation_desc.index: # First issue date for each citation type citation_desc['first_date'].ix[row] = min(groupby_desc['violDate'].get_group(row)) # Last issue date for each citation type citation_desc['last_date'].ix[row] = max(groupby_desc['violDate'].get_group(row)) # Total date range in years for each citation type citation_desc['date_range_years'] = (citation_desc['last_date'] - citation_desc['first_date']).astype('timedelta64[D]')/365. # Fines per year for each citation type citation_desc['fines_annual'] = citation_desc['fines']/citation_desc['date_range_years'] citation_desc.head() #citation_desc.to_csv('citation_desc_date_range_new.csv') # takes a long time! df_time = df.fillna(0).set_index(df['violDate']) # takes a long time! df_time['ImportDate_parsed'] = pd.to_datetime(df_time['ImportDate']) df_time.sort(inplace=True) df_time.head() # Monthly totals for all citations df_time['violFine'].resample('M',how='count').plot() # Plot top 10 infraction types over time fig = plt.figure(figsize=[10,8]) for key in citation_desc[:10].index: #print key df_time['violFine_parsed'][df_time['Description']==key].resample('M', how='count').plot(label=key,grid='off') xlabel('') ylabel('Number of Citations') legend(loc='upper left') #fig.savefig('Top 10 Monthly Citation Plot 2015-01-21.png', bbox_tight='inches') # Monthly mobile speed cameras df_time['violCode'][df_time['Description']=='Mobile Speed Camera'].resample('M',how='count').plot() # Total value of fines issued in database before January 21, 2013 df_time['violFine_parsed'][df_time.index <= pd.to_datetime('21-jan-2013')].sum() df_time[(df_time.index <= pd.to_datetime('21-jan-2013')) & (df_time['balance_parsed']==0)] df_time[(df_time['ImportDate_parsed'] <= pd.to_datetime('21-jan-2013')) & (df_time['balance_parsed']==0)] df_time_rec = df_time.ix['21-jan-2013':'21-jan-2015'] total_balance = df_time['balance_parsed'].sum() total_fines = df_time['violFine_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() total_pen = df_time['openPenalty_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() print total_balance, total_fines, total_pen total_fines+total_pen (total_fines+total_pen)/total_balance total_pen/total_balance df_time['balance_parsed'][df_time['balance_parsed']==0].count() df_time['openFine_parsed'].sum()+df_time['openPenalty_parsed'].sum() df_time['balance_parsed'].sum() df_time['violFine_parsed'].sum() df_time['openPenalty_parsed'].sum() df_time['balance_parsed'].sum() - (df_time['openFine_parsed'].sum()+df_time['openPenalty_parsed'].sum()) df_time['violFine_parsed'][df_time['balance_parsed']==0].sum() df_time['balance_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() df_time['violFine_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() df_time['openPenalty_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() df_time['openFine_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() df_time['openPenalty_parsed'].ix['21-jan-2013':'21-jan-2015'].sum()+df_time['openFine_parsed'].ix['21-jan-2013':'21-jan-2015'].sum() df_time['balance_parsed'].ix[:'20-jan-2013'].sum() df_time['violFine_parsed'].ix[:'20-jan-2013'].sum() df_time['balance_parsed'].ix[:'20-jan-2013'].sum()/df_time['violFine_parsed'].ix[:'20-jan-2013'].sum() df_time_2 = df_time.ix['01-feb-2013':'28-feb-2015'] df_time_2['violFine_parsed'].resample('M',how='count').plot() groupby_desc2 = df_time_2.groupby('Description') citation_desc2 = pd.DataFrame() # Total fines for each citation type citation_desc2['fines'] = groupby_desc2['violFine_parsed'].sum() # Number of unique locations each citation type was issued at citation_desc2['unique_locs'] = groupby_desc2['location'].nunique() # Fine type concentration by location citation_desc2['fine_conc_loc'] = (citation_desc2['fines'] / citation_desc2['unique_locs']).apply(lambda x: round(x,2)) citation_desc2.sort('fines',inplace=True,ascending=False) citation_desc2['first_date'] = '' citation_desc2['last_date'] = '' for row in citation_desc2.index: # First issue date for each citation type citation_desc2['first_date'].ix[row] = min(groupby_desc2['violDate'].get_group(row)) # Last issue date for each citation type citation_desc2['last_date'].ix[row] = max(groupby_desc2['violDate'].get_group(row)) # Total date range in years for each citation type citation_desc2['date_range_years'] = (citation_desc2['last_date'] - citation_desc2['first_date']).astype('timedelta64[D]')/365. # Fines per year for each citation type citation_desc2['fines_annual'] = citation_desc2['fines']/citation_desc2['date_range_years'] citation_desc2 #citation_desc.to_csv('citation_desc_date_range_new.csv') # Plot top 10 infraction types over time fig = plt.figure(figsize=[10,8]) ax1 = plt.subplot(111) for key in citation_desc2[:10].index: #print key df_time_2['violFine_parsed'][df_time_2['Description']==key].ix['01-feb-2013':'31-dec-2014'].resample('M', how='count').plot(linewidth=2,label=key,grid='off') # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) xlabel('') ylabel('Number of Citations', fontsize=14) legend(loc='upper left', fontsize=12) title('Top 10 Citation Types (by Total Fines)\n 01-Feb-2013 to 31-Dec-2014', fontsize=18) #fig.savefig('output/Top 10 Monthly Citation Plot 2013-02-01 to 2014-12-31.png', bbox_tight='inches') groupby_loc = df_time_2.groupby(df_time_2['location']) loc_counts = groupby_loc['Description'].count() loc_revenue = groupby_loc['violFine_parsed'].sum() loc_counts.sort(inplace=True, ascending=False) loc_revenue.sort(inplace=True, ascending=False) print '\nNumber of locations:', loc_revenue.count() print 'Number of locations with fines issued greater than $10,000: ', loc_revenue[loc_revenue>=10000].count() print '% of all locations with fines issued greater than $10,000:', round(100*float(loc_revenue[loc_revenue>=10000].count()) / float(loc_revenue.count()),1) print '% Revenue generated by locations with fines issued greater than $10,000:', round(100*loc_revenue[loc_revenue>=10000].sum() / loc_revenue.sum(),1),'\n' loc_revenue.hist(bins=50) loc_revenue[:20].to_csv('output/Top20_Target_locations.csv') df_time_2[:-30] fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(111) plot(df_time_2.resample('M', how='count').index, df_time_2['tag'][df_time_2['openFine_parsed']==0].resample('M', how='count')/df_time_2['tag'].resample('M', how='count'), linewidth=2, color=red_orange) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) plt.ylim([0,1]) plt.xticks(rotation=45) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) title('% Monthly Citations Records With No Open Balance\n', fontsize=16) plt.subplots_adjust(top=0.9, bottom=0.15) fig.savefig('output/Monthly_Records_Paid.png', bbox_tight='inches') red_orange = '#FF3300' fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(111) plot(df_time_2.resample('M', how='count').index, df_time_2['balance_parsed'][df_time_2['violFine_parsed']>0].resample('M', how='sum')/df_time_2['violFine_parsed'].resample('M', how='sum'), linewidth=2, color=red_orange) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) plt.ylim([0,1.1]) plt.xticks(rotation=45) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) title('% Monthly Citations Records With No Open Balance\n', fontsize=18) df_time_2.resample('M', how='count').index block_1200_Charles = groupby_loc.get_group('1200 CHARLES ST').groupby('Description') print 'Fines Issued at 1200 N. Charles St.\n' block_1200_Charles_fines = pd.DataFrame(columns=['total_fines_issued']) for key, group in block_1200_Charles: #print key, block_1200_Charles['violFine_parsed'].get_group(key).sum() block_1200_Charles_fines.ix[key] = block_1200_Charles['violFine_parsed'].get_group(key).sum() block_1200_Charles_fines.sort('total_fines_issued',ascending=False, inplace=True) block_1200_Charles_fines.to_csv('output/1200_Block_N_Charles.csv') block_1200_Charles_fines block_1200_Charles['violFine_parsed'].get_group(key).sum() groupby_loc.get_group('1200 CHARLES ST').groupby('Description').count() (df_time_2['violFine_parsed'].resample('D',how='sum')/df_time_2['balance_parsed'].resample('D',how='sum')).plot() (df_time_2['balance_parsed'].resample('M',how='sum')/df_time_2['violFine_parsed'].resample('M',how='sum')).plot() (df_time_2['balance_parsed'][df_time_2['balance_parsed']==0].resample('M',how='count')/df_time_2['violFine_parsed'].resample('M',how='count')).plot() df_time_2['balance_parsed'][df_time_2['balance_parsed']==0].resample('M',how='count') df_time_2['violFine_parsed'].resample('M',how='count') fig = plt.figure() (df_time_2['openFine_parsed'].resample('D',how='sum')/df_time_2['violFine_parsed'].resample('D',how='sum')).plot() (df_time_2['openPenalty_parsed'].resample('D',how='sum')/df_time_2['violFine_parsed'].resample('D',how='sum')).plot() plt.grid('off') legend(['Total Open Fines / Total Fines','Total Open Penalties / Total Fines']) fig = plt.figure() (df_time_2['balance_parsed'][df_time_2['balance_parsed']==0].resample('M',how='count')/df_time_2['violFine_parsed'].resample('M',how='count')).plot() plt.grid('off') #legend(['Total Open Fines / Total Fines','Total Open Penalties / Total Fines']) import plotly.plotly as py fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(1,1,1) plot1 = (df_time_2['openFine_parsed'].resample('D',how='sum')/df_time_2['violFine_parsed'].resample('D',how='sum')).plot(color=red_orange) #(df_time_2['openPenalty_parsed'].resample('D',how='sum')/df_time_2['violFine_parsed'].resample('D',how='sum')).plot() linear_ext = pd.DataFrame([.03, .11],index=[pd.to_datetime('01-feb-2013'),pd.to_datetime('20-dec-2013')]) plot2 = linear_ext[0].plot(color=red_orange, linestyle='--', linewidth=3) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) plt.ylim([0,1.1]) #plt.xticks(rotation=45) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) plt.title('% Daily Total Fines Issued Remaining Unpaid', fontsize=18) plt.xlabel('') plt.grid('off') #fig.savefig('output/Daily_Total_Fines_Unpaid.png', bbox_tight='inches') #py.iplot_mpl(fig) fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(1,1,1) plot1 = (df_time_2['openFine_parsed'][df_time_2['openFine_parsed']>0].resample('D',how='count')/df_time_2['violFine_parsed'].resample('D',how='count')).plot(color=red_orange) #(df_time_2['openPenalty_parsed'].resample('D',how='sum')/df_time_2['violFine_parsed'].resample('D',how='sum')).plot() linear_ext = pd.DataFrame([.03, .11],index=[pd.to_datetime('01-feb-2013'),pd.to_datetime('20-dec-2013')]) plot2 = linear_ext[0].plot(color=red_orange, linestyle='--', linewidth=3) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) plt.ylim([0,1.1]) #plt.xticks(rotation=45) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) plt.title('% Daily Number Citations Issued Remaining Unpaid', fontsize=18) plt.xlabel('') plt.grid('off') #fig.savefig('output/Daily_Citations_Unpaid.png', bbox_tight='inches') df_time_2['openFine_parsed'].resample('D',how='count') #df_time_2['openFine_parsed'][df_time_2['openFine_parsed']>0].resample('D',how='count') df_time_2['city'] = 'Baltimore' df_time_2['state'] = 'MD' #df_time_2[['location','city','state']].ix['2013'].to_csv('output/2013_citation_locations.csv') #df_time_2[['location','city','state']].ix['2014'].to_csv('output/2014_citation_locations.csv') # Random samples for mapping purposes N = 1000 df_2013 = df_time_2[['tag','location','city','state']].ix['2013'] df_2014 = df_time_2[['tag','location','city','state']].ix['2014'] sample_2013 = df_2013.iloc[np.random.choice(len(df_2013), N, replace=False)] #sample_2013.to_csv('output/2013_random_sample.csv') sample_2014 = df_2014.iloc[np.random.choice(len(df_2014), N, replace=False)] #sample_2014.to_csv('output/2014_random_sample.csv') block_1200_Charles['violFine_parsed'].plot() df_time_2['violFine_parsed'][df_time_2['location']=='1200 CHARLES ST'].resample('M',how='sum').plot() np.std(df_time_2['violFine_parsed'].ix['2014'].resample('D',how='sum')) np.std(df_time_2['violFine_parsed'].ix['2013'].resample('D',how='sum')) # Overall monthly citation increase fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(1,1,1) plot1 = df_time_2['violFine_parsed'].ix[:'dec-2014'].resample('M',how='count').plot(color=red_orange, grid='off',linewidth=3) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) #plt.ylim([0,1.1]) #plt.xticks(rotation=45) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) plt.ylabel('Total Monthly Number of Citations', fontsize=16) plt.xlabel('') #fig.savefig('output/Total_Monthly_Citations.png', bbox_tight='inches') # % Increase Sept 2013 to Mar 2014 print 'Overall Ratio, March 2014 citations to September 2013 citations: ',round(float(df_time_2['violFine_parsed'].ix['mar-2014'].count()) / float(df_time_2['violFine_parsed'].ix['sept-2013'].count()), 2) # FIRST NEED TO SLICE OUT ONLY LOCATIONS WITH TICKETS IN Sep 2013 and Mar 2014 #sep13_uniq_locs = df_time_2['location'].ix['sep-2013'].unique() mar14_uniq_locs = df_time_2['location'].ix['mar-2014'].unique() a = df_time_2[df_time_2['location'].isin(mar14_uniq_locs)] #b = a[a['location'].isin(mar14_uniq_locs)] Mar14_Sep13 = pd.DataFrame() Mar14_Sep13['Mar_2014'] = a['location'].ix['Mar-2014'].value_counts() Mar14_Sep13['Sept_2013'] = a['location'].ix['Sept-2013'].value_counts() Mar14_Sep13['Sept_2013'].fillna(0, inplace=True) Mar14_Sep13['Diff'] = Mar14_Sep13['Mar_2014'] - Mar14_Sep13['Sept_2013'] Mar14_Sep13['Ratio'] = Mar14_Sep13['Mar_2014'] / Mar14_Sep13['Sept_2013'] Mar14_Sep13.sort('Diff', ascending=False, inplace=True) Mar14_Sep13[:25] #Mar14_Sep13[:25].to_csv('output/Top_25_Increase_Citations_Sept13_Mar14_Locs.csv') df_time_2['tag'][df_time_2['location']=='400 LOT JFA'].ix[:'dec-2014'].resample('M', how='count').plot() a = df_time_2[df_time_2['location']=='400 LOT JFA'].groupby('Description') a['tag'].count() df_time_2['tag'][df_time_2['location']=='3200 LOT WAVERLY'].ix[:'dec-2014'].resample('M', how='count').plot() fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(1,1,1) plot1 = df_time_2['tag'][df_time_2['location']=='5100 ROLAND AVE'].ix[:'dec-2014'].resample('M', how='count').plot(grid='off', color=red_orange, linewidth=3) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) #plt.ylim([0,1.1]) #plt.xticks(rotation=45) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) plt.ylabel('Total Monthly Number of Citations', fontsize=16) plt.xlabel('') plt.title('5100 Roland Ave.', fontsize=16) #fig.savefig('output/5100_Roland_Citations.png', bbox_tight='inches') a = df_time_2[df_time_2['location']=='5100 ROLAND AVE'].groupby('Description') a['tag'].count() fig = plt.figure(figsize=[10,6]) ax1 = plt.subplot(1,1,1) # convert resampled index to right date format my_x_labels = df_time_2['violFine_parsed'][df_time_2['location']=='4200 WICKFORD RD'].resample('M',how='count').index.map(lambda x: x.strftime('%b %Y')) plot1= bar(xrange(len(my_x_labels)), df_time_2['violFine_parsed'][df_time_2['location']=='4200 WICKFORD RD'].resample('M',how='count'), align='center', color=red_orange) xlim([0,len(my_x_labels)]) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) plt.xticks(xrange(len(df_time_2['violFine_parsed'][df_time_2['location']=='4200 WICKFORD RD'].resample('M',how='count'))),my_x_labels,ha='center',rotation=90) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) #title('4200 Wickford Rd.', fontsize=20) text(len(my_x_labels)-1,24,'4200 Wickford Rd.',ha='right',fontsize=20) plt.subplots_adjust(top=0.95, bottom=0.2) ylabel('Monthly Ticket Count', fontsize=16) #fig.savefig('output/4200_Wickford.png', bbox_tight='inches') df_time_2['violFine_parsed'][df_time_2['location']=='4200 WICKFORD RD'].count()#.to_csv('output/4200_Wickford_Citations.csv') df_time_2['Description'][df_time_2['location']=='4200 WICKFORD RD']#.to_csv('output/4200_Wickford_Citations.csv') Charles_St = ['900 CHARLES ST', '1000 CHARLES ST', '1100 CHARLES ST', '1200 CHARLES ST', '1300 CHARLES ST'] # All days Charles_St_citations = df_time_2[df_time_2['location'].isin(Charles_St)] Charles_St_hour_count = Charles_St_citations['tag'].groupby(Charles_St_citations.index.hour).count() bar(Charles_St_hour_count.index,Charles_St_hour_count) # Charles St Weekend Charles_St_citations_weekend = Charles_St_citations.ix[(Charles_St_citations.index.dayofweek==5) | (Charles_St_citations.index.dayofweek==6)] Charles_St_citations_weekend_hour_count = Charles_St_citations_weekend['tag'].groupby(Charles_St_citations_weekend.index.hour).count() bar(Charles_St_citations_weekend_hour_count.index,Charles_St_citations_weekend_hour_count,align='center') xlim([-1,24]) plt.show() #Charles_St_citations_weekday = Charles_St_citations.index.dayofweek.isin([0,1,2,3,4]) # Charles St Weekday Charles_St_citations_weekday = Charles_St_citations.ix[Charles_St_citations.index.dayofweek<5] Charles_St_citations_weekday_hour_count = Charles_St_citations_weekday['tag'].groupby(Charles_St_citations_weekday.index.hour).count() bar(Charles_St_citations_weekday_hour_count.index,Charles_St_citations_weekday_hour_count,align='center') xlim([-1,24]) plt.show() # Total citation counts on 5 blocks of N. Charles St. by day of week fig = plt.figure(figsize=[8,6]) ax1 = plt.subplot(1,1,1) my_x_labels = ['Mon','Tues','Weds','Thurs','Fri','Sat','Sun'] a=Charles_St_citations.groupby(Charles_St_citations.index.dayofweek) a['tag'].count().plot(kind='bar', grid='off', color=red_orange) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) text(6.25,2500,'N. Charles St. \n Citations',ha='right',va='center',fontsize=20) ylabel('Citations', fontsize=16) xticks(range(0,7),my_x_labels, rotation=0) plt.show() fig.savefig('output/N_Charles_by_Day.png', bbox_tight='inches') Charles_St_citations.groupby('Description')['tag'].count() fig = plt.figure(figsize=[10,8]) ax1 = plt.subplot(1,1,1) a=pd.DataFrame(pd.Series(Charles_St_citations_weekday.index.hour).value_counts(),index=range(0,23)) b=pd.DataFrame(pd.Series(Charles_St_citations_weekend.index.hour).value_counts(),index=range(0,23)) b.fillna(0,inplace=True) a.sort(inplace=True) b.sort(inplace=True) bar(b.index,b[0],color=light_cyan,align='center') bar(a.index,a[0],color=gray_light,bottom=b[0],align='center') xlim([-1,24]) xlabel('Hour of Day', fontsize=16) ylabel('Citations', fontsize=16) text(0,2000,'N. Charles St. Citations',ha='left',va='center',fontsize=20) legend(['Weekend','Weekday'],loc='upper left', fontsize=16, frameon=False, bbox_to_anchor=(.14, -.13, 1, 1), bbox_transform=gcf().transFigure) # turn off square border around plot ax1.spines["top"].set_visible(False) ax1.spines["bottom"].set_visible(False) ax1.spines["right"].set_visible(False) ax1.spines["left"].set_visible(False) # turn off ticks ax1.tick_params(axis="both", which="both", bottom="off", top="off", labelbottom="on", left="off", right="off", labelleft="on",labelsize=14) fig.savefig('output/N_Charles_by_Hour.png', bbox_inches='tight') b Charles_St_citations