'Filling In the Area Between Two Lines with a Custom Color Gradient

I am working on an assignment that I have pretty much already completed, but I wanted to add a small touch to it that attempts to fill the area between the two lines with a colormap based on temperature instead of just a simple color. The way the lines are plotted makes them separate entities essentially, so I know that I'll likely need two colormaps that meet each other or overlap to accomplish this but I'm not too sure how to accomplish this. Any assistance is greatly appreciated.

from datetime import datetime
import pandas as pd
import numpy as np
import matplotlib.colors as mcol
import matplotlib.cm as cm
bin = 400
hash = 'fb441e62df2d58994928907a91895ec62c2c42e6cd075c2700843b89'

Temp = pd.read_csv('fb441e62df2d58994928907a91895ec62c2c42e6cd075c2700843b89.csv'.format(bin, hash))

Temp['Date'] = pd.to_datetime(Temp['Date'])

#Only doing this here because the mplleaflet in my personal jupyter notebook is bugged
#will take longer to execute, will take more lines of code for conversions and ultimately is less efficient than simply doing it with pandas. 
#print(datetime.strptime(Temp['Date'].to_json(), '%y-%m-%d')) = datetime.strptime(Temp['Date'], format)

Temp['Y'] = Temp['Date'].dt.year
Temp['M'] = Temp['Date'].dt.month
Temp['D'] = Temp['Date'].dt.day
Temp['DV'] = Temp['Data_Value'].div(10)
Temp['E'] = Temp['Element']

Temp = Temp[~((Temp['M']==2) & (Temp['D']==29))]
GrMin = Temp[(Temp['E']=='TMIN') & (Temp['Y']>=2005) & (Temp['Y']<2015)].groupby(['M','D']).agg({'DV':np.min})
FinMin = Temp[(Temp['E']=='TMIN') & (Temp['Y']==2015)].groupby(['M','D']).agg({'DV':np.min})
GrMax = Temp[(Temp['E']=='TMAX') & (Temp['Y']>=2005) & (Temp['Y']<2015)].groupby(['M','D']).agg({'DV':np.max})
FinMax = Temp[(Temp['E']=='TMIN') & (Temp['Y']==2015)].groupby(['M','D']).agg({'DV':np.max})
#x = GrMax
#y = GrMin
#X, Y = np.meshgrid(x,y)
#Z = f(X, Y)

AnomMin = FinMin[FinMin['DV'] < GrMin['DV']]
AnomMax = FinMax[FinMax['DV'] > GrMax['DV']]

#temps = range(-30,40)

plt.figure(figsize=(18, 10), dpi = 80)
red = '#FF0000'
blue = '#0800FF'
cm1 = mcol.LinearSegmentedColormap.from_list('Temperature Map',[blue, red])
cnorm = mcol.Normalize(vmin=min(GrMin['DV']),vmax=max(GrMax['DV']))
cpick = cm.ScalarMappable(norm=cnorm,cmap=cm1)
cpick.set_array([])
plt.title('Historical Temperature Analysis In Ann Arbor Michigan')
plt.xlabel('Month')
plt.ylabel('Temperature in Celsius')
plt.plot(GrMax.values, c = red, linestyle = '-', label = 'Highest Temperatures (2005-2014)')
#plt.scatter(AnomMax, FinMax.iloc[AnomMax], c = red, s=5, label = 'Anomolous High Readings (2015)')
plt.plot(GrMin.values, c = blue, linestyle = '-', label = 'Lowest Temperatures (2005-2014)')
#plt.scatter(AnomMin, FinMin.iloc[AnomMin], c = blue, s=5, label = 'Anomolous Low Readings (2015)')
plt.xticks(np.linspace(0,60 + 60*11, num=12),(r'January',r'February',r'March',r'April',r'May',r'June',r'July',r'August',r'September',r'October',r'November',r'December'))

#Failed Attempt
#plt.contourf(X, Y, Z, 20, cmap = cm1)
#for i in temps
#    plt.fill_between(len(GrMin['DV']), GrMin['DV'], i ,cmap = cm1)
#for i in temps
#    plt.fill_between(len(GrMin['DV']), i ,GrMax['DV'], cmap = cm1)

#Kind of Close but doesn't exactly create the colormap
plt.gca().fill_between(range(len(GrMin.values)), GrMin['DV'], GrMax['DV'], cmap = cm1)

plt.legend(loc = '0', title='Temperature Guide')
plt.colorbar(cpick, label='Temperature in Celsius')
plt.show()

Current result:
enter image description here



Solution 1:[1]

After correcting some functional errors within my code then applying the code provided by JohanC as well as asking for some other much-needed guidance, I was able to successfully complete the colormap. It would probably be more visually appealing if the upper and lower line plots were a different color but as far as the colormap is concerned, mission accomplished. Thanks again for the assistance!

from datetime import datetime
import pandas as pd
import numpy as np
import matplotlib.colors as mcol
import matplotlib.cm as cm
bin = 400
hash = 'fb441e62df2d58994928907a91895ec62c2c42e6cd075c2700843b89'

Temp = pd.read_csv('fb441e62df2d58994928907a91895ec62c2c42e6cd075c2700843b89.csv'.format(bin, hash))

Temp['Date'] = pd.to_datetime(Temp['Date'])

#Only doing this here because the mplleaflet in my personal jupyter notebook is bugged
#will take longer to execute, will take more lines of code for conversions and ultimately is less efficient than simply doing it with pandas. 
#print(datetime.strptime(Temp['Date'].to_json(), '%y-%m-%d')) = datetime.strptime(Temp['Date'], format)

Temp['Y'] = Temp['Date'].dt.year
Temp['M'] = Temp['Date'].dt.month
Temp['D'] = Temp['Date'].dt.day
Temp['DV'] = Temp['Data_Value'].div(10)
Temp['E'] = Temp['Element']

Temp = Temp[~((Temp['M']==2) & (Temp['D']==29))]
GrMin = Temp[(Temp['E']=='TMIN') & (Temp['Y']>=2005) & (Temp['Y']<2015)].groupby(['M','D']).agg({'DV':np.min})
FinMin = Temp[(Temp['E']=='TMIN') & (Temp['Y']==2015)].groupby(['M','D']).agg({'DV':np.min})
GrMax = Temp[(Temp['E']=='TMAX') & (Temp['Y']>=2005) & (Temp['Y']<2015)].groupby(['M','D']).agg({'DV':np.max})
FinMax = Temp[(Temp['E']=='TMAX') & (Temp['Y']==2015)].groupby(['M','D']).agg({'DV':np.max})

GrMax = GrMax.reset_index() 
GrMin = GrMin.reset_index() 
FinMax = FinMax.reset_index() 
FinMin = FinMin.reset_index() 

#x = GrMax
#y = GrMin
#X, Y = np.meshgrid(x,y)
#Z = f(X, Y)

AnomMin = FinMin[FinMin['DV'] < GrMin['DV']]
AnomMax = FinMax[FinMax['DV'] > GrMax['DV']]

#temps = range(-30,40)

plt.figure(figsize=(18, 10), dpi = 160)
red = '#FF0000'
blue = '#0800FF'
cm1 = mcol.LinearSegmentedColormap.from_list('Temperature Map',[blue, red])
cnorm = mcol.Normalize(vmin=min(GrMin['DV']),vmax=max(GrMax['DV']))
cpick = cm.ScalarMappable(norm=cnorm,cmap=cm1)
cpick.set_array([])
plt.title('Historical Temperature Analysis In Ann Arbor Michigan')
plt.xlabel('Month')
plt.ylabel('Temperature in Celsius')
plt.plot(GrMax['DV'], c = red, linestyle = '-', label = 'Highest Temperatures (2005-2014)')
plt.scatter(AnomMax.index, AnomMax['DV'], c = red, s=2, label = 'Anomolous High Readings (2015)')
plt.plot(GrMin['DV'], c = blue, linestyle = '-', label = 'Lowest Temperatures (2005-2014)')
plt.scatter(AnomMin.index, AnomMin['DV'], c = blue, s=2, label = 'Anomolous Low Readings (2015)')
plt.xticks(np.linspace(0,365,12, endpoint = True),(r'January',r'February',r'March',r'April',r'May',r'June',r'July',r'August',r'September',r'October',r'November',r'December'))

#Start: Assisted from StackOverFlow user JohanC v

x = np.arange(len(GrMin['DV'].fillna(0).astype('float64').ravel()))
y1 = GrMax['DV'].fillna(0).astype('float64').ravel()
y2 = GrMin['DV'].fillna(0).astype('float64').ravel()


polygon = plt.fill_between(x, y1, y2, lw=0, color='none')
xlim = (x.min(), x.max())
ylim = plt.ylim()
verts = np.vstack([p.vertices for p in polygon.get_paths()])
gradient = plt.imshow(np.linspace(1, 0, 256).reshape(-1, 1), cmap=cm1, aspect='auto',
                      extent=[verts[:, 0].min(), verts[:, 0].max(), verts[:, 1].min(), verts[:, 1].max()])
gradient.set_clip_path(polygon.get_paths()[0], transform=plt.gca().transData)
plt.xlim(xlim)
plt.ylim(ylim)

#Finish: Assisted from StackOverFlow user JohanC ^

#Failed Attempt at gradient fill with colormap
#plt.contourf(X, Y, Z, 20, cmap = cm1)
#for i in temps
#    plt.fill_between(len(GrMin['DV']), GrMin['DV'], i ,cmap = cm1)
#for i in temps
#    plt.fill_between(len(GrMin['DV']), i ,GrMax['DV'], cmap = cm1)

#Kind of Close but doesn't exactly create the colormap
#plt.gca().fill_between(range(len(GrMin.values)), GrMin['DV'], GrMax['DV'], facecolor = 'grey', alpha = 0.10)

plt.legend(loc = 'lower center', title='Temperature Guide')
plt.colorbar(cpick, label='Temperature in Celsius')
plt.show()

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 gQuery