Plotting record temperatures for New Orleans

The temperature trends in New Orleans over the period 2005-2015 is plotted using the python libraries pandas and matplotlib to generate a clear graph:

In the graph, the record highs and lows in the temperature over the period 2005-2014 are given as line graphs and the record breaking temperatures for the year 2015 are scattered over as red and blue dots.

Each row in the datafile corresponds to a single observation. There are four columns in the datafile as follows:

ID : station identification code

Date : date in YYYY-MM-DD format (e.g. 2012-01-24 = January 24, 2012)

Element : indicator of element type

TMAX : Maximum temperature

TMIN : Minimum temperature

Data_Value : data value for element (tenths of degrees C)

The temperatures are given at tenths of degrees celsius and are taken from multiple locations in New Orleans at multiple
times of the day everyday from Jan 01, 2005 to Dec 31, 2015.

df.head(5)

ID

Date

Element

Data_Value

0

USW00053917

2005-07-06

TMAX

306

1

USW00012884

2011-10-05

TMIN

211

2

USC00168941

2014-09-16

TMIN

233

3

USC00166676

2012-07-20

TMIN

239

4

USC00168941

2009-04-22

TMAX

283

The dataframe df is now prepared to extract the data in desired format:

df.loc[:,'Data_Value']*=0.1# Dividing all temperature entries by 10 to convert them to degree celsiusdf['Date']=pd.to_datetime(df['Date'])# Changing the dtype of the date to pandas datetime # Setting up the sorted multi-index consisting of month and days so as to help grouping rows later for each # day of the yeardf['Day']=pd.DatetimeIndex(df['Date']).daydf['Month']=pd.DatetimeIndex(df['Date']).monthdf=df.set_index(['Month','Day'])df.sort_index(inplace=True)# Discarding all the entries for 29th Feb of any year; only 365 days of the year are consideredselected_df=df.loc[2,29]df=df[~df.index.isin(selected_df.index)]

# Splitting dataframes into two - one for 2005-2014 and another for 2015df['Year']=pd.DatetimeIndex(df['Date']).yeardf_2015=df[df['Year']==2015]df=df[df['Year']!=2015]# Creating two dataframes for 2005-2014 - one each for max and minmax_temp_df=df[df['Element']=='TMAX']min_temp_df=df[df['Element']=='TMIN']# The following gives pandas series with 365 entries corresponding to the max/min temperatures # over the decade 2005-2014 for each day of the yearmax_temp=max_temp_df.groupby(level=['Month','Day'])['Data_Value'].max()min_temp=min_temp_df.groupby(level=['Month','Day'])['Data_Value'].min()# Creating two dataframes for 2015 - one each for max and minmax_temp_df_2015=df_2015[df_2015['Element']=='TMAX']min_temp_df_2015=df_2015[df_2015['Element']=='TMIN']# The following gives dataframes with 365 rows corresponding to the max/min temperatures for each day of # the year 2015 and two columns in total viz one for temperature values and another for dates stored # as the pandas datatime object max_temp_df_2015=max_temp_df_2015.groupby(level=['Month','Day']).max()[['Data_Value','Date']]min_temp_df_2015=min_temp_df_2015.groupby(level=['Month','Day']).min()[['Data_Value','Date']]

Plotting graphs for record high and low temperatures for each day of the year over the period 2005-2014 using matplotlib:

importmatplotlib.pyplotaspltimportmatplotlib.datesasdatesimportmatplotlib.tickerasticker# Need 365 days array for plotting in pandas datetime format; year does not matter so taken 2015 # for conveniencedate_range=df_2015['Date'].unique()# Creating figure and an axisfig,ax=plt.subplots(nrows=1,ncols=1,figsize=(10,5))ax.set_title('New Orleans Record Temperatures (2005-2014) and 2015')# Setting the titleax.yaxis.grid()# Setting up the horizontal grid lines in the background# Plotting graphs and filling in between region# Google Material Design color palette (https://material.io/guidelines/style/color.html) is used below: plt.plot(date_range,max_temp.values,'#FF9100',linewidth=1,alpha=0.75,label='2005-2014 Highs')plt.plot(date_range,min_temp.values,'#80D8FF',linewidth=1,alpha=0.75,label='2005-2014 Lows')plt.fill_between(date_range,min_temp,max_temp,facecolor='#EEEEEE')

Adding semi-transparent legend with no border:

plt.legend(loc=1).get_frame().set_edgecolor('white')# Labels for the legends of the scatter plots belowmy_label_max="2015 Highs"my_label_min="2015 Lows"

Scattering record breaking temperatures from the year 2015 as red and blue dots over the graph:

foridx,rowsinmax_temp_df_2015.iterrows():ifrows['Data_Value']>max_temp.loc[idx]:plt.scatter(rows['Date'],rows['Data_Value'],c='#E65100',marker='.',label=my_label_max)my_label_max="_nolegend_"# To avoid duplicate labels in the legendforidx,rowsinmin_temp_df_2015.iterrows():ifrows['Data_Value']<min_temp.loc[idx]:plt.scatter(rows['Date'],rows['Data_Value'],c='#0091EA',marker='.',label=my_label_min)my_label_min="_nolegend_"# Adding the labels for the max and min points to the above legend ax.legend(loc=1).get_frame().set_edgecolor('white')

This is to set up the x-axis:

# Setting the limits for x-axis to fit the dates perfectlyxmin,xmax=date_range[0],date_range[-1]ax.set_xlim(xmin,xmax)# Locating 12 positions for the 15th of each month on x-axis ax.xaxis.set_major_locator(dates.MonthLocator())ax.xaxis.set_minor_locator(dates.MonthLocator(bymonthday=15))# Labeling the 12 months on x-axis at the positions located aboveax.xaxis.set_major_formatter(ticker.NullFormatter())ax.xaxis.set_minor_formatter(dates.DateFormatter('%b'))# Centering month labels in between the ticks and removing undesirable ticksxticks=ax.xaxis.get_minor_ticks()forxtickinxticks:xtick.tick1line.set_markersize(0)xtick.tick2line.set_markersize(0)xtick.label1.set_horizontalalignment('center')

This is to set up the left y-axis for temperatures in Celsius:

ax.set_ylabel('Temperatures $(^{\circ}$C)')# Set label for y-axis# Setting the temperature limits for y-axis from -10 to 50 degrees Celsiusymin,ymax=-10,50ax.set_ylim(ymin,ymax)yticks=ax.yaxis.get_major_ticks()yticks[0].label1.set_visible(False)# Making 50 degrees Celsius disappear to make the graph look cleaneryticks[1].label1.set_visible(False)# Making -10 degrees Celsius disappear to make the graph look cleanerax.yaxis.set_major_locator(ticker.MultipleLocator(10))# Putting major ticks at every 10 degrees Celsiusax.yaxis.set_minor_locator(ticker.MultipleLocator(5))# Putting minor ticks at every 5 degrees Celsius

This is to set up the right y-axis for temperatures in Fahrenheit:

ax2=ax.twinx()# Create a twin y-axis sharing the x-axis with the previous y-axisax2.set_ylabel('Temperatures $(^{\circ}$F)')# Setting label for y-axisdefC_to_F(temp_c):# Celsius to Fahrenheit return9/5*temp_c+32ax2.set_ylim(C_to_F(ymin),C_to_F(ymax))# (ymin, ymax) are defined aboveax2.yaxis.set_major_locator(ticker.MultipleLocator(20))# Putting major ticks at every 20 degrees Fahrenheitax2.yaxis.set_minor_locator(ticker.MultipleLocator(5))# Putting major ticks at every 5 degrees Fahrenheit