-
-
Save pwolfram/f38717b4d7343c8ed886 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Copyright: This document has been placed in the public domain. | |
""" | |
Taylor diagram (Taylor, 2001) test implementation. | |
http://www-pcmdi.llnl.gov/about/staff/Taylor/CV/Taylor_diagram_primer.htm | |
""" | |
__version__ = "Time-stamp: <2012-02-17 20:59:35 ycopin>" | |
__author__ = "Yannick Copin <[email protected]>" | |
import numpy as NP | |
import matplotlib.pyplot as PLT | |
class TaylorDiagram(object): | |
"""Taylor diagram: plot model standard deviation and correlation | |
to reference (data) sample in a single-quadrant polar plot, with | |
r=stddev and theta=arccos(correlation). | |
""" | |
def __init__(self, refstd, fig=None, rect=111, label='_'): | |
"""Set up Taylor diagram axes, i.e. single quadrant polar | |
plot, using mpl_toolkits.axisartist.floating_axes. refstd is | |
the reference standard deviation to be compared to. | |
""" | |
from matplotlib.projections import PolarAxes | |
import mpl_toolkits.axisartist.floating_axes as FA | |
import mpl_toolkits.axisartist.grid_finder as GF | |
self.refstd = refstd # Reference standard deviation | |
tr = PolarAxes.PolarTransform() | |
# Correlation labels | |
rlocs = NP.concatenate((NP.arange(10)/10.,[0.95,0.99])) | |
tlocs = NP.arccos(rlocs) # Conversion to polar angles | |
gl1 = GF.FixedLocator(tlocs) # Positions | |
tf1 = GF.DictFormatter(dict(zip(tlocs, map(str,rlocs)))) | |
# Standard deviation axis extent | |
self.smin = 0 | |
self.smax = 1.5*self.refstd | |
ghelper = FA.GridHelperCurveLinear(tr, | |
extremes=(0,NP.pi/2, # 1st quadrant | |
self.smin,self.smax), | |
grid_locator1=gl1, | |
tick_formatter1=tf1, | |
) | |
if fig is None: | |
fig = PLT.figure() | |
ax = FA.FloatingSubplot(fig, rect, grid_helper=ghelper) | |
fig.add_subplot(ax) | |
# Adjust axes | |
ax.axis["top"].set_axis_direction("bottom") # "Angle axis" | |
ax.axis["top"].toggle(ticklabels=True, label=True) | |
ax.axis["top"].major_ticklabels.set_axis_direction("top") | |
ax.axis["top"].label.set_axis_direction("top") | |
ax.axis["top"].label.set_text("Correlation") | |
ax.axis["left"].set_axis_direction("bottom") # "X axis" | |
ax.axis["left"].label.set_text("Standard deviation") | |
ax.axis["right"].set_axis_direction("top") # "Y axis" | |
ax.axis["right"].toggle(ticklabels=True) | |
ax.axis["right"].major_ticklabels.set_axis_direction("left") | |
ax.axis["bottom"].set_visible(False) # Useless | |
# Contours along standard deviations | |
ax.grid(False) | |
self._ax = ax # Graphical axes | |
self.ax = ax.get_aux_axes(tr) # Polar coordinates | |
# Add reference point and stddev contour | |
print "Reference std:", self.refstd | |
l, = self.ax.plot([0], self.refstd, 'k*', | |
ls='', ms=10, label=label) | |
t = NP.linspace(0, NP.pi/2) | |
r = NP.zeros_like(t) + self.refstd | |
self.ax.plot(t,r, 'k--', label='_') | |
# Collect sample points for latter use (e.g. legend) | |
self.samplePoints = [l] | |
def add_sample(self, stddev, corrcoef, *args, **kwargs): | |
"""Add sample (stddev,corrcoeff) to the Taylor diagram. args | |
and kwargs are directly propagated to the Figure.plot | |
command.""" | |
l, = self.ax.plot(NP.arccos(corrcoef), stddev, | |
*args, **kwargs) # (theta,radius) | |
self.samplePoints.append(l) | |
return l | |
def add_contours(self, levels=5, **kwargs): | |
"""Add constant centered RMS difference contours.""" | |
rs,ts = NP.meshgrid(NP.linspace(self.smin,self.smax), | |
NP.linspace(0,NP.pi/2)) | |
# Compute centered RMS difference | |
rms = NP.sqrt(self.refstd**2 + rs**2 - 2*self.refstd*rs*NP.cos(ts)) | |
contours = self.ax.contour(ts, rs, rms, levels, **kwargs) | |
return contours | |
if __name__=='__main__': | |
# Reference dataset | |
x = NP.linspace(0,4*NP.pi,100) | |
data = NP.sin(x) | |
refstd = data.std(ddof=1) # Reference standard deviation | |
# Models | |
m1 = data + 0.2*NP.random.randn(len(x)) # Model 1 | |
m2 = 0.8*data + .1*NP.random.randn(len(x)) # Model 2 | |
m3 = NP.sin(x-NP.pi/10) # Model 3 | |
# Compute stddev and correlation coefficient of models | |
samples = NP.array([ [m.std(ddof=1), NP.corrcoef(data, m)[0,1]] | |
for m in (m1,m2,m3)]) | |
fig = PLT.figure(figsize=(10,4)) | |
ax1 = fig.add_subplot(1,2,1, xlabel='X', ylabel='Y') | |
# Taylor diagram | |
dia = TaylorDiagram(refstd, fig=fig, rect=122, label="Reference") | |
colors = PLT.matplotlib.cm.jet(NP.linspace(0,1,len(samples))) | |
ax1.plot(x,data,'ko', label='Data') | |
for i,m in enumerate([m1,m2,m3]): | |
ax1.plot(x,m, c=colors[i], label='Model %d' % (i+1)) | |
ax1.legend(numpoints=1, prop=dict(size='small'), loc='best') | |
# Add samples to Taylor diagram | |
for i,(stddev,corrcoef) in enumerate(samples): | |
dia.add_sample(stddev, corrcoef, marker='s', ls='', c=colors[i], | |
label="Model %d" % (i+1)) | |
# Add RMS contours, and label them | |
contours = dia.add_contours(colors='0.5') | |
PLT.clabel(contours, inline=1, fontsize=10) | |
# Add a figure legend | |
fig.legend(dia.samplePoints, | |
[ p.get_label() for p in dia.samplePoints ], | |
numpoints=1, prop=dict(size='small'), loc='upper right') | |
PLT.show() | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
__version__ = "Time-stamp: <2012-08-13 16:52 ycopin@lyopc469>" | |
__author__ = "Yannick Copin <[email protected]>" | |
""" | |
Example of use of TaylorDiagram. Illustration dataset courtesy of | |
Michael Rawlins. | |
Rawlins, M. A., R. S. Bradley, H. F. Diaz, 2012. Assessment of | |
regional climate model simulation estimates over the Northeast U.S., | |
Journal of Geophysical Research, in review. | |
""" | |
from taylorDiagram import TaylorDiagram | |
import numpy as NP | |
import matplotlib.pyplot as PLT | |
# Reference std | |
stdrefs = dict(winter=48.491, | |
spring=44.927, | |
summer=37.664, | |
autumn=41.589) | |
# Sample std,rho: Be sure to check order and that correct numbers are placed! | |
samples = dict(winter=[[17.831, 0.360, "CCSM CRCM"], | |
[27.062, 0.360, "CCSM MM5"], | |
[33.125, 0.585, "CCSM WRFG"], | |
[25.939, 0.385, "CGCM3 CRCM"], | |
[29.593, 0.509, "CGCM3 RCM3"], | |
[35.807, 0.609, "CGCM3 WRFG"], | |
[38.449, 0.342, "GFDL ECP2"], | |
[29.593, 0.509, "GFDL RCM3"], | |
[71.215, 0.473, "HADCM3 HRM3"]], | |
spring=[[32.174, -0.262, "CCSM CRCM"], | |
[24.042, -0.055, "CCSM MM5"], | |
[29.647, -0.040, "CCSM WRFG"], | |
[22.820, 0.222, "CGCM3 CRCM"], | |
[20.505, 0.445, "CGCM3 RCM3"], | |
[26.917, 0.332, "CGCM3 WRFG"], | |
[25.776, 0.366, "GFDL ECP2"], | |
[18.018, 0.452, "GFDL RCM3"], | |
[79.875, 0.447, "HADCM3 HRM3"]], | |
summer=[[35.863, 0.096, "CCSM CRCM"], | |
[43.771, 0.367, "CCSM MM5"], | |
[35.890, 0.267, "CCSM WRFG"], | |
[49.658, 0.134, "CGCM3 CRCM"], | |
[28.972, 0.027, "CGCM3 RCM3"], | |
[60.396, 0.191, "CGCM3 WRFG"], | |
[46.529, 0.258, "GFDL ECP2"], | |
[35.230, -0.014, "GFDL RCM3"], | |
[87.562, 0.503, "HADCM3 HRM3"]], | |
autumn=[[27.374, 0.150, "CCSM CRCM"], | |
[20.270, 0.451, "CCSM MM5"], | |
[21.070, 0.505, "CCSM WRFG"], | |
[25.666, 0.517, "CGCM3 CRCM"], | |
[35.073, 0.205, "CGCM3 RCM3"], | |
[25.666, 0.517, "CGCM3 WRFG"], | |
[23.409, 0.353, "GFDL ECP2"], | |
[29.367, 0.235, "GFDL RCM3"], | |
[70.065, 0.444, "HADCM3 HRM3"]]) | |
# Colormap (see http://www.scipy.org/Cookbook/Matplotlib/Show_colormaps) | |
colors = PLT.matplotlib.cm.Set1(NP.linspace(0,1,len(samples['winter']))) | |
# Here set placement of the points marking 95th and 99th significance | |
# levels. For more than 102 samples (degrees freedom > 100), critical | |
# correlation levels are 0.195 and 0.254 for 95th and 99th | |
# significance levels respectively. Set these by eyeball using the | |
# standard deviation x and y axis. | |
#x95 = [0.01, 0.68] # For Tair, this is for 95th level (r = 0.195) | |
#y95 = [0.0, 3.45] | |
#x99 = [0.01, 0.95] # For Tair, this is for 99th level (r = 0.254) | |
#y99 = [0.0, 3.45] | |
x95 = [0.05, 13.9] # For Prcp, this is for 95th level (r = 0.195) | |
y95 = [0.0, 71.0] | |
x99 = [0.05, 19.0] # For Prcp, this is for 99th level (r = 0.254) | |
y99 = [0.0, 70.0] | |
rects = dict(winter=221, | |
spring=222, | |
summer=223, | |
autumn=224) | |
fig = PLT.figure(figsize=(11,8)) | |
fig.suptitle("Precipitations", size='x-large') | |
for season in ['winter','spring','summer','autumn']: | |
dia = TaylorDiagram(stdrefs[season], fig=fig, rect=rects[season], | |
label='Reference') | |
dia.ax.plot(x95,y95,color='k') | |
dia.ax.plot(x99,y99,color='k') | |
# Add samples to Taylor diagram | |
for i,(stddev,corrcoef,name) in enumerate(samples[season]): | |
dia.add_sample(stddev, corrcoef, | |
marker='$%d$' % (i+1), ms=10, ls='', | |
#mfc='k', mec='k', # B&W | |
mfc=colors[i], mec=colors[i], # Colors | |
label=name) | |
# Add RMS contours, and label them | |
contours = dia.add_contours(levels=5, colors='0.5') # 5 levels | |
dia.ax.clabel(contours, inline=1, fontsize=10, fmt='%.1f') | |
# Tricky: ax is the polar ax (used for plots), _ax is the | |
# container (used for layout) | |
dia._ax.set_title(season.capitalize()) | |
# Add a figure legend and title. For loc option, place x,y tuple inside [ ]. | |
# Can also use special options here: | |
# http://matplotlib.sourceforge.net/users/legend_guide.html | |
fig.legend(dia.samplePoints, | |
[ p.get_label() for p in dia.samplePoints ], | |
numpoints=1, prop=dict(size='small'), loc='center') | |
fig.tight_layout() | |
PLT.savefig('test_taylor_4panel.png') | |
PLT.show() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment