# Plot Taylor diagrams

**URL:** <https://discourse.julialang.org/t/plot-taylor-diagrams/56406>\
**Category:** Visualization\
**Created:** [March 3, 2021, 1:25pm UTC](https://discourse.julialang.org/t/plot-taylor-diagrams/56406 "2021-03-03T13:25:00Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![rio](https://avatars.discourse-cdn.com/v4/letter/r/ea666f/32.png) [@rio](https://discourse.julialang.org/u/rio)\
**Post date:** [March 3, 2021, 1:25pm UTC](https://discourse.julialang.org/t/plot-taylor-diagrams/56406/1 "2021-03-03T13:25:00Z")

</div>

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:

> **[Taylor diagram](https://en.wikipedia.org/wiki/Taylor_diagram)**
>
> Taylor diagrams are mathematical diagrams designed to graphically indicate which of several approximate representations (or models) of a system, process, or phenomenon is most realistic. This diagram, invented by Karl E. Taylor in 1994 (published in 2001) facilitates the comparative assessment of different models. It is used to quantify the degree of correspondence between the modeled and observed behavior in terms of three statistics: the Pearson correlation coefficient, the root-mean-squa Al...

Please, do you have any suggestions?  
Thanks in advance.

---

<div class="post-metadata">

**Author:** ![SimonT](https://avatars.discourse-cdn.com/v4/letter/s/a88e4f/32.png) [@SimonT](https://discourse.julialang.org/u/SimonT)\
**Post date:** [October 2, 2022, 2:49pm UTC](https://discourse.julialang.org/t/plot-taylor-diagrams/56406/2 "2022-10-02T14:49:46Z")

</div>

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 !

> **[GitHub - SimonTreillou/TaylorDiag.jl: Github repo about Taylor diagram...](https://github.com/SimonTreillou/TaylorDiag.jl)**
>
> Github repo about Taylor diagram implementation in Julia. - GitHub - SimonTreillou/TaylorDiag.jl: Github repo about Taylor diagram implementation in Julia.

Have a nice day

Simon

---

<div class="post-metadata">

**Author:** ![mreichMPI-BGC](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mreichmpi-bgc/32/43775_2.png) [@mreichMPI-BGC](https://discourse.julialang.org/u/mreichMPI-BGC)\
**Post date:** [November 22, 2022, 8:45am UTC](https://discourse.julialang.org/t/plot-taylor-diagrams/56406/3 "2022-11-22T08:45:44Z")

</div>

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-repl
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:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/8/8/8891178ac322621c7998ed38f09e9d1210b6ee57.png)

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

---

<div class="post-metadata">

**Author:** ![briochemc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/briochemc/32/4209_2.png) [@briochemc](https://discourse.julialang.org/u/briochemc)\
**Post date:** [February 11, 2025, 7:34am UTC](https://discourse.julialang.org/t/plot-taylor-diagrams/56406/4 "2025-02-11T07:34:16Z")

</div>

Update from [Makie.jl issue #4771](https://github.com/MakieOrg/Makie.jl/issues/4771):

 ![](https://global.discourse-cdn.com/julialang/original/3X/7/7/77b98ec7de17c17a1979173475fe606da65e2d06.png)

Code:

```julia
# Taylor plot
using CairoMakie
using Statistics

function taylordiagramvalues(f, r, args...)

    # STDs and means
    σf = std(f, args...; corrected = false)
    σr = std(r, args...; corrected = false)
    f̄ = mean(f, args...)
    r̄ = mean(r, args...)

    # Correlation coefficient
    R = cor(f, r, args...)

    # Root Mean Square Difference
    E = sqrt(mean((f .- r) .^ 2, args...))

    # Bias
    Ē = f̄ - r̄

    # Centered Root Mean Square Difference
    E′ = sqrt(mean(((f .- f̄) - (r .- r̄)) .^ 2, args...))

    # Full Mean Square Difference
    E² = E′^2 + Ē^2

    # Normalized values (maybe that needs to be a kwarg)
    Ê′ = E′ / σr
    σ̂f = σf / σr
    σ̂r = 1.0

    return (; σr, σf, R, E, Ē, E′, E², Ê′, σ̂f, σ̂r)
end

# model data is a vector (list) of N-dimensional arrays
# copied values from https://easyclimate.readthedocs.io/en/latest/auto_gallery_output/plot_taylor_diagram.html#sphx-glr-download-auto-gallery-output-plot-taylor-diagram-py
model_data = [
    [1 , 2 , 3 , 0.1, 0.2, 0.3, 3.2, 0.6, 1.8],
    [0.2, 0.4, 0.6, 15 , 10 , 5 , 3.2, 0.6, 1.8]
]
obs_data = sum(model_data) / 1.85

# Calculate the Taylor diagram values
TDvals = [taylordiagramvalues(data, obs_data) for data in model_data]
σr = TDvals[1].σr
σmax = 2.7TDvals[1].σr

# Do the actual plotting now
# First, construct the figure and a polar axis on the first quadrant
fig = Figure(size=(600, 600))

# Corrticks for Taylor diagram
corrticks = [-1; -0.99; -0.95; -0.9:0.1:-0.7; -0.6:0.2:0.6; 0.7:0.1:0.9; 0.95; 0.99; 1.0]

ax = PolarAxis(fig[1, 1];
    thetalimits = (0, π), # first quadrant only
    thetagridcolor = (:black, 0.5),
    thetagridstyle = :dot,
    thetaticks = (acos.(corrticks), string.(corrticks)),
    # thetaminorticks,
    rlimits = (0, σmax),
    rgridcolor = cgrad(:Archambault, categorical = true)[1],
    rticklabelcolor = cgrad(:Archambault, categorical = true)[1],
    rgridstyle = :dash,
    rticks = 0:1:σmax,
)

# Create isolines of root centered mean squared difference (E′) and labels
levels = (0.5:0.5:4) .* σr
rgrid = (0:0.01:1) .* σmax
θgrid = (0:0.01:π)
E′grid = [sqrt(σr^2 + r^2 - 2 * σr * r * cos(θ)) for θ in θgrid, r in rgrid]
contour!(ax, θgrid, rgrid, E′grid;
    levels,
    labels = true,
    color = cgrad(:Archambault, categorical = true)[3]
)

# Now, plot the actual data
σfs = [vals.σf for vals in TDvals]
Rs = [vals.R for vals in TDvals]

# Transform data to Cartesian space?
"A transformation function that goes from correlation and standard deviation to the Taylor plot's Cartesian space."
xy_from_R_and_σ(R, σ) = Point2(σ * R, sqrt(σ^2 - (σ * R)^2))
x, y = collect.(zip(xy_from_R_and_σ.([Rs; 1], [σfs; σr])...) |> collect)
# Above I used R = 1 and σr for the reference point

scatter!(ax, x, y;
    color = [:red, :green, :black],
    marker = [:cross, :star5, :circle],
    transformation = Transformation(ax.scene.transformation; transform_func = identity)
)

fig

```
