I am trying to map the difference between climate simulation data and observed data over a set geographical area.
To create the map of just the climate simulation I am using this code
import matplotlib.pyplot as plt
import iris
import iris.plot as iplt
import cartopy
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import iris.analysis.cartography
def main():
#bring in all the models we need and give them a name
CCCma = '/exports/csce/datastore/geos/users/s0XXXX/Climate_Modelling/AFR_44_tas/ERAINT/1979-2012/tas_AFR-44_ECMWF-ERAINT_evaluation_r1i1p1_CCCma-CanRCM4_r2_mon_198901-200912.nc'
#Load exactly one cube from given file
CCCma = iris.load_cube(CCCma)
#we are only interested in the latitude and longitude relevant to Malawi
Malawi = iris.Constraint(grid_longitude=lambda v: 31 <= v <= 36.5, \
grid_latitude=lambda v: -18. <= v <= -8.)
CCCma = CCCma.extract(Malawi)
#time constraint to make all series the same
iris.FUTURE.cell_datetime_objects = True
t_constraint = iris.Constraint(time=lambda cell: 1989 <= cell.point.year <= 2008)
CCCma = CCCma.extract(t_constraint)
#Convert units to match, CORDEX data is in Kelvin but Observed data in Celsius, we would like to show all data in Celsius
CCCma.convert_units('Celsius')
#plot map with physical features
cmap = plt.cm.afmhot_r
ax = plt.axes(projection=cartopy.crs.PlateCarree())
ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS)
ax.add_feature(cartopy.feature.LAKES, alpha=0.5)
ax.add_feature(cartopy.feature.RIVERS)
#set map boundary
ax.set_extent([31, 36.5, -8,-18])
#set axis tick marks
ax.set_xticks([32, 34, 36])
ax.set_yticks([-9, -11, -13, -15, -17])
lon_formatter = LongitudeFormatter(zero_direction_label=True)
lat_formatter = LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)
data = CCCma
#take mean of data over all time
plot = iplt.contourf(data.collapsed('time', iris.analysis.MEAN), \
cmap=cmap, levels=[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],\
extend='both')
#add colour bar index
plt.colorbar(plot)
#give map a title
plt.title('RCP4.5 Mean Temperature 1989-2008', fontsize=10)
plt.show()
if __name__ == '__main__':
main()
How can I amend this to take the difference between the two datasets? I tried this code:
import matplotlib.pyplot as plt
import iris
import iris.plot as iplt
import cartopy
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
import iris.analysis.cartography
#this file is split into parts as follows:
#PART 1: load and format CORDEX models
#PART 2: load and format observed data
#PART 3: format data
#PART 4: plot data
def main():
#PART 1: CORDEX MODELS
#bring in all the models we need and give them a name
CCCma = '/exports/csce/datastore/geos/users/s0XXXX/Climate_Modelling/AFR_44_tas/ERAINT/1979-2012/tas_AFR-44_ECMWF-ERAINT_evaluation_r1i1p1_CCCma-CanRCM4_r2_mon_198901-200912.nc'
#Load exactly one cube from given file
CCCma = iris.load_cube(CCCma)
#we are only interested in the latitude and longitude relevant to Malawi
Malawi = iris.Constraint(grid_longitude=lambda v: 31 <= v <= 36.5, \
grid_latitude=lambda v: -18. <= v <= -8.)
CCCma = CCCma.extract(Malawi)
#time constraint to make all series the same
iris.FUTURE.cell_datetime_objects = True
t_constraint = iris.Constraint(time=lambda cell: 1989 <= cell.point.year <= 2008)
CCCma = CCCma.extract(t_constraint)
#PART 2: OBSERVED DATA
#bring in all the files we need and give them a name
CRU= '/exports/csce/datastore/geos/users/s0XXXX/Climate_Modelling/Actual_Data/cru_ts4.00.1901.2015.tmp.dat.nc'
#Load exactly one cube from given file
CRU = iris.load_cube(CRU, 'near-surface temperature')
#we are only interested in the latitude and longitude relevant to Malawi
Malawi = iris.Constraint(longitude=lambda v: 32.5 <= v <= 36., \
latitude=lambda v: -17. <= v <= -9.)
CRU = CRU.extract(Malawi)
#time constraint to make all series the same
iris.FUTURE.cell_datetime_objects = True
t_constraint = iris.Constraint(time=lambda cell: 1989 <= cell.point.year <= 2008)
CRU = CRU.extract(t_constraint)
#PART 3: FORMAT DATA
#Convert units to match
CCCma.convert_units('Celsius')
CRU.convert_units('Celsius')
#Take difference between two datasets
Bias_CCCma = CCCma-CRU
#PART 4: PLOT MAP
#plot map with physical features
cmap = plt.cm.afmhot_r
ax = plt.axes(projection=cartopy.crs.PlateCarree())
ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS)
ax.add_feature(cartopy.feature.LAKES, alpha=0.5)
ax.add_feature(cartopy.feature.RIVERS)
#set map boundary
ax.set_extent([31, 36.5, -8,-18])
#set axis tick marks
ax.set_xticks([32, 34, 36])
ax.set_yticks([-9, -11, -13, -15, -17])
lon_formatter = LongitudeFormatter(zero_direction_label=True)
lat_formatter = LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)
data = Bias_CCCma
#take mean of data over all time
plot = iplt.contourf(data.collapsed('time', iris.analysis.MEAN), \
cmap=cmap, levels=[15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],\
extend='both')
#add colour bar index
plt.colorbar(plot)
#give map a title
plt.title('RCP4.5 Mean Temperature 1989-2008', fontsize=10)
plt.show()
if __name__ == '__main__':
main()
However this gives me the following error:
ValueError: This operation cannot be performed as there are differing coordinates (grid_latitude, grid_longitude, time) remaining which cannot be ignored.
I was pretty sure this wasn't going to be so simple, but I'm not sure how to fix it. Any ideas? TIA!
My guess is that CCCma and CRU are on different grids, so when you try to subtract them you get an error. You probably need to interpolate them to the same grid first (otherwise, how would
irisknow which grid you want the result to lie on?).