# Plot Taylor diagrams

I am looking for a Julia function to create a Taylor diagram (a diagram that compares measured against estimated values for a certain variable), like in:

Please, do you have any suggestions?

3 Likes

Hi @rio, you should already have fixed your problem, but if not, and if other people are willing to make Taylor diagrams in Julia, I can offer you the small module I made to plot the Taylor diagram. Itâ€™s made using Plots.jl â€śfrom handsâ€ť and as for now works quite well. If you have specific requests we can see what to do and obviously the repo is open for pull requests and contributions !

Have a nice day

Simon

Here is what I ported from my ggplot2 to Julia as personal learning exercise (you know).

Tried to quick add some description. Far from perfect, as youâ€™ll see. Happy to see improvements of the plotting :-).

Btw. I donâ€™t understand why it accepts scalar, although I type it to Array{Number}. Putting scalar causes problem with arrrows!

``````taylor_plot(sdmod_rel::Array{Number}, correl::Array{Number}; bias=0.0, sdObs=1.0, plotBias=false, plotVarianceErr=false)
``````

#### Create an (extended) Taylorplot.

Given the modelâ€™s standard deviation relative to the observations `sdmod_rel`, the correlation with the
observations `correl`, and optionally the `bias`, an extended Taylor plot is created. Extended means, that apart
from the classical one (zero centered residuals, no bias) a point including the bias (indicated with an arrows
towards this point) and also a point under the scenario â€ś= no variance errorâ€ť (again with arrow) is plotted,
when `plotBias` and `plotVarianceErr` are `true`. `sdObs` is the standard deviation of the observations (it just scales the
axes essentially.)

Please note that `sdmod_rel` and `correl` need to be Arrays (otherwise `arrows!` does not work), so for only one point
wrap it in `[`â€¦].

### Examples

``````julia> taylor_plot([0.8,1.2], [0.8, 0.5], bias=0.2, plotBias=true, plotVarianceErr=true)

``````
``````function taylor_plot(sdmod_rel::Array{Number}, correl::Array{Number}; bias=0.0, sdObs=1.0,   plotBias=false, plotVarianceErr=false)
sdmax = max(maximum(sdmod_rel), 1.0)

## Function to transform coordinates
correl_sd2taylor(sd, correl) = (x=correl * sd, y=sqrt(sd^2-(correl*sd)^2))

## Create Taylorplot gridlines
correls = reduce(vcat,[-1, -0.99, -0.95, -0.9:0.1:0.9, 0.95, 0.99, 1.0])
sds = 0:0.1:sdmax |> collect

fig, ax, sc = scatter(0,0, color=(:black, 0));
for c in correls
lines!(ax, c .* sds .* sdObs * 1.02, sqrt.(sds.^2-(c .* sds).^2).*sdObs * 1.02; linestyle= :dot, color=:grey)
end

for s in sds
lines!(ax, correls .* s .* sdObs, sqrt.(s.^2 .- (correls .* s).^2).*sdObs; linestyle= s==1 ? :dash : :dot, color=:grey)
end

## Creat isolines of root mean squared difference (RMSD) and labels
RMSD = 0.2:0.2:2*sdmax+0.2 |> collect
xvec =  -1.0:0.01:1 |> collect

rmsd_lab_x=Vector{Float64}()
rmsd_lab_y=Vector{Float64}()
rmsd_lab_text=Vector{String}()

for r in RMSD[1:end-1]

x2 = @. (xvec * r + 1) * sdObs
y2 = @. sqrt(1-xvec^2) * r * sdObs

i_plot = [i for i in 1:length(x2) if sqrt(x2[i]^2+y2[i]^2)<=1.005*maximum(sds)*sdObs]

# This also works, but not if the array sent back by the compr is empty (collect does not work)
# xp, yp = zip([(xi,yi) for (xi, yi) in zip(x2, y2) if sqrt(xi^2+yi^2)<=1.005*maximum(sds)*sdObs]...) |> collect

lines!(ax, x2[i_plot], y2[i_plot], color=(:blue, 0.5))

i_lab=[i for i in 1:length(x2) if (y2[i]>0.3^2*sdObs^2/abs(x2[i])) & (x2[i]>0.0) & (sqrt(x2[i]^2+y2[i]^2)<=1.005*maximum(sds)*sdObs)]
if length(i_lab)>0
push!(rmsd_lab_x, x2[i_lab[1]])
push!(rmsd_lab_y, y2[i_lab[1]])
push!(rmsd_lab_text, "\$(round(r, digits=2))")
end

end

#### Plotting data in Taylor space

x,y = collect.(zip(correl_sd2taylor.(sdmod_rel, correl)...) |> collect) .* sdObs

# First the arrows, so that the point is always on top
if plotBias
RMSD = @. sqrt(sdObs^2 + (sdmod_rel*sdObs)^2 - 2*sdObs^2*sdmod_rel*correl)
RMSE = @. sqrt(bias^2+RMSD^2)
RMSDangle = @. asin(y/RMSD)
RMSEangle = @. asin(bias/RMSE)
alpha = @. ifelse(x > sdObs, Ď€ - RMSDangle - RMSEangle, RMSDangle - RMSEangle)
xb = @. sdObs - cos(alpha)* RMSE
yb = @. sin(alpha) * RMSE
arrows!(x, y, xb.-x, yb.-y; color=1:length(x), linewidth=3)
end

if plotVarianceErr
x_no_var_err, y_no_var_err = collect.(zip(correl_sd2taylor.(1.0, correl)...) |> collect) .* sdObs
arrows!(x,y, x_no_var_err.-x, y_no_var_err.-y; color=1:length(x), linewidth=3)
end

# if (plotNoVarErr) {
#     modPointsNoVarErr <- correl_sd2Taylor(1, correl) * sdObs
#     p  <- p + geom_point(data=modPointsNoVarErr, mapping=aes(x,y), color="red", size=2, alpha=0.5)

## Plot data points (original Taylorplot)
scatter!(ax, x, y, color=1:length(x),  strokewidth=0.5, glowwidth = 5.0, glowcolor=(:black,0.5) )

## Plot point of "perfect model"
scatter!(ax, sdObs, 0.0, markersize=20, color=(:blue,0.5))

### Labels for coordinate system
correlTicks = @pipe reduce(vcat, [-0.9:0.1:0.9, 0.95, 0.99]) |> setdiff(_, [0])
text!(correlTicks*sdmax*sdObs*1.04, sqrt.(sdmax^2 .- (correlTicks*sdmax).^2)*sdObs*1.04,
text=["\$(round(c, digits=2))" for c in correlTicks], align=(:center,:center), textsize=10)
#scatter!(correlTicks*sdmax*sdObs*1.04, sqrt.(sdmax^2 .- (correlTicks*sdmax).^2)*sdObs*1.04)
scatter!(rmsd_lab_x,rmsd_lab_y, markersize=(30,20), color=:white, strokewidth=0.5)
text!(rmsd_lab_x,rmsd_lab_y, text=rmsd_lab_text, align=(:center,:center), textsize=10)

## Clipping plot
xlims!(ax, min(0, 1.1*minimum(x)), max(sdObs,1.1*maximum(x)))

(fig, ax)

# taylor_grid = @pipe Base.product(correls, sds) |> DataFrame |> rename(_, [:correls, :sds])

# iso_rmsd = @pipe Base.product(0.2:0.2:2*sdmax+0.2 |> collect, -1.0:0.01:1 |> collect) |>
#     DataFrame |> rename(_, [:RMSD, :xvec])

# @chain iso_rmsd begin
#     @rtransform! begin
#         :x2 = (:xvec * :RMSD + 1)* sdObs
#         :y2 = sqrt(1-:xvec^2)*:RMSD*sdObs
#     end
#     @rsubset! sqrt(:x2^2+:y2^2)<=1.005*maximum(taylor_grid.sds)*sdObs
# end

# @rtransform! taylor_grid :xv = :correls*:sds
# @rtransform! taylor_grid begin
#     :yv = sqrt(:sds^2-:xv^2)*sdObs
#     :xv=:xv*sdObs
# end
# @transform! taylor_grid begin
# :sdsCat = categorical(:sds)
# :correlCat = categorical(:correls)
# end

# #plt = data(taylor_grid) * visual(Lines, linestyle=:dash) *  mapping(:xv, :yv, group=(:correlCat, :sdsCat))
# #plt += data(taylor_grid) * visual(Lines, linestyle=:dash) *  mapping(:xv, :yv, group=:sdsCat)
# #draw(plt; axis=(width = 1225, height = 825))
# fig=Figure()

end
``````

Youâ€™ll get this:

P.S.: Quite proud to have posted my first maybe helpful Julia code

5 Likes