Commit fcddb351 authored by saeed's avatar saeed
Browse files

clean version of taylor diagram

parent e2252ca2
# Copyright: This document has been placed in the public domain.
Taylor diagram (Taylor, 2001) implementation.
__version__ = "Time-stamp: <2017-11-24 18:01:03 ycopin>"
__author__ = "Yannick Copin <>"
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
def __init__(self, refstd, fig=None, rect=111, label='_', srange=(0, 1.0)):
Set up Taylor diagram axes, i.e. single quadrant polar
plot, using `mpl_toolkits.axisartist.floating_axes`.
* refstd: reference standard deviation to be compared to
* fig: input Figure or None
* rect: subplot definition
* label: reference label
* srange: stddev axis extension, in units of *refstd*
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 (in units of reference stddev)
self.smin = srange[0]*self.refstd
self.smax = srange[1]*self.refstd
ghelper = FA.GridHelperCurveLinear(tr,
extremes=(0, np.pi/2, # 1st quadrant
self.smin, self.smax),
if fig is None:
fig = plt.figure()
ax = FA.FloatingSubplot(fig, rect, grid_helper=ghelper)
# Adjust axes
ax.axis["top"].set_axis_direction("bottom") # "Angle axis"
ax.axis["top"].toggle(ticklabels=True, label=True)
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["bottom"].set_visible(False) # Useless
self._ax = ax # Graphical axes = ax.get_aux_axes(tr) # Polar coordinates
# Add reference point and stddev contour
l, =[0], self.refstd, 'k*',
ls='', ms=10, label=label)
t = np.linspace(0, np.pi/2)
r = np.zeros_like(t) + self.refstd, 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, =, stddev,
*args, **kwargs) # (theta,radius)
return l
def add_grid(self, *args, **kwargs):
"""Add a grid."""*args, **kwargs)
def add_contours(self, levels=5, **kwargs):
Add constant centered RMS difference contours, defined by *levels*.
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 =, rs, rms, levels, **kwargs)
return contours
def test1():
"""Display a Taylor diagram in a separate axis."""
# Reference dataset
x = np.linspace(0, 4*np.pi, 100)
data = np.sin(x)
refstd = data.std(ddof=0) # Reference standard deviation
# Generate 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 =, 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 the models to Taylor diagram
for i, (stddev, corrcoef) in enumerate(samples):
dia.add_sample(stddev, corrcoef,
marker='$%d$' % (i+1), ms=10, ls='',
mfc=colors[i], mec=colors[i],
label="Model %d" % (i+1))
# Add grid
# Add RMS contours, and label them
contours = dia.add_contours(colors='0.5')
plt.clabel(contours, inline=1, fontsize=10, fmt='%.2f')
# Add a figure legend
[ p.get_label() for p in dia.samplePoints ],
numpoints=1, prop=dict(size='small'), loc='upper right')
return fig
def test2():
Climatology-oriented example (after iteration w/ Michael A. Rawlins).
# Reference std
stdref = 48.491
# Samples std,rho,name
samples = [[25.939, 0.385, "Model A"],
[29.593, 0.509, "Model B"],
[33.125, 0.585, "Model C"],
[29.593, 0.509, "Model D"],
[71.215, 0.473, "Model E"],
[27.062, 0.360, "Model F"],
[38.449, 0.342, "Model G"],
[35.807, 0.609, "Model H"],
[17.831, 0.360, "Model I"]]
fig = plt.figure()
dia = TaylorDiagram(stdref, fig=fig, label='Reference')
dia.samplePoints[0].set_color('r') # Mark reference point as a red star
# Add models to Taylor diagram
for i, (stddev, corrcoef, name) in enumerate(samples):
dia.add_sample(stddev, corrcoef,
marker='$%d$' % (i+1), ms=10, ls='',
mfc='k', mec='k',
# Add RMS contours, and label them
contours = dia.add_contours(levels=5, colors='0.5') # 5 levels in grey
plt.clabel(contours, inline=1, fontsize=10, fmt='%.0f')
# Add a figure legend and title
[ p.get_label() for p in dia.samplePoints ],
numpoints=1, prop=dict(size='small'), loc='upper right')
fig.suptitle("Taylor diagram", size='x-large') # Figure title
return fig
if __name__ == '__main__':
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment