-
-
Notifications
You must be signed in to change notification settings - Fork 322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Taylor diagram #4771
Comments
Segfaults definitely shouldn't be happening...could you unpack the function (or just insert I tried to adapt this to a polar axis: # Taylor plot
# INPUT
sdmod_rel = [0.8,1.2]
correl = [0.8, 0.5]
bias=0.2
sd_obs = 1.0
plot_bias = true
plot_variance_error = true
# Do the actual plotting now
# First, construct the figure and a polar axis on the first quadrant
fig = Figure()
ax = PolarAxis(fig[1, 1])
ax.thetalimits[] = (0, pi/2) # first quadrant only
# Now, style the axis appropriately for a Taylor plot
ax.thetagridcolor = (:black, 0.1)
ax.thetagridstyle = :dash
# Now, go forth and plot!
# First, plot the grid lines for the correlation
# TODO: it would be better if we had labelled lines
# plucked from the contour recipe,
# but since we don't, we can do this manually.
"A transformation function that goes from correlation and standard deviation to the Taylor plot's Cartesian space."
correl_sd2taylor_transf = Makie.PointTrans{2}() do (correl, sd)
Point2(correl * sd, sqrt(sd^2-(correl*sd)^2)) * sd_obs
end
correl_sd2taylor(sd, correl) = (x=correl * sd, y=sqrt(sd^2-(correl*sd)^2))
## Create Taylorplot gridlines
# sdmax = max(maximum(sdmod_rel), 1.0)
# 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
# Create isolines of root mean squared difference (RMSD) and labels
RMSD = 0.2:0.2:2*sdmax+0.2
xvec = -1.0:0.01:1
for r in RMSD[1:end-1]
# this is slightly different from the "true transform"
# so we compute the points directly and plot in corrected space
points = @. Point2f((xvec * r + 1) * sd_obs, sqrt(1-xvec^2) * r * sd_obs)
points_inds = splat(hypot).(points) .<= 1.005 * (maximum(sds)) * sd_obs
lines!(ax,
points[points_inds];
color=(:blue, 0.5),
transformation = Transformation(ax.scene.transformation; transform_func = identity),
xautolimits = false,
yautolimits = false,
# label = "RMSD $r"
) # each line gets a label, so they should be separate
end
# Now, plot the actual data
# First the arrows
xy_orig = Point2f.(sdmod_rel, correl)
x,y = collect.(zip(correl_sd2taylor.(sdmod_rel, correl)...) |> collect) .* sd_obs
xy = Point2f.(x,y)
if plot_bias
# here we want to be in Cartesian space, since we're calculating angles
RMSD = @. sqrt(sd_obs^2 + (sdmod_rel*sd_obs)^2 - 2*sd_obs^2*sdmod_rel*correl)
RMSE = @. sqrt(bias^2+RMSD^2)
RMSDangle = @. atan(y/RMSD)
RMSEangle = @. atan(bias/RMSE)
alpha = @. ifelse(x > sd_obs, π - RMSDangle - RMSEangle, RMSDangle - RMSEangle)
xb = @. sd_obs - cos(alpha)* RMSE
yb = @. sin(alpha) * RMSE
arrows!(ax, x, y, xb.-x, yb.-y; color=1:length(x), linewidth=3, transformation = Transformation(ax.scene.transformation; transform_func = identity))
end
if plot_variance_error
# this should also be in Cartesian space because the vector subtraction has to happen there.
xy_no_var_err = Point2f.(1.0, correl)
xy_no_var_err = Makie.apply_transform(correl_sd2taylor_transf, xy_no_var_err)
arrows!(ax, xy, xy_no_var_err .- xy; color=1:length(xy), linewidth=3, transformation = Transformation(ax.scene.transformation; transform_func = identity))
end
fig but the arrows seem wrong...maybe there's an issue with how I am going from one space to another? Ideally one has some kind of |
🤔 I was trying your code and I am getting a segfault again (GLMakie v0.10.18): julia> for r in RMSD[1:end-1]
# this is slightly different from the "true transform"
# so we compute the points directly and plot in corrected space
points = @. Point2f((xvec * r + 1) * sd_obs, sqrt(1-xvec^2) * r * sd_obs)
points_inds = splat(hypot).(points) .<= 1.005 * (maximum(sds)) * sd_obs
lines!(ax,
points[points_inds];
color=(:blue, 0.5),
transformation = Transformation(ax.scene.transformation; transform_func = identity),
xautolimits = false,
yautolimits = false,
# label = "RMSD $r"
) # each line gets a label, so they should be separate
end
# Now, plot the actual data
# First the arrows
[49476] signal 11 (1): Segmentation fault: 11
in expression starting at none:0
gleRunVertexSubmitImmediate at /System/Library/Frameworks/OpenGL.framework/Versions/A/Resources/GLEngine.bundle/GLEngine (unknown line)
gleDrawArraysOrElements_ExecCore at /System/Library/Frameworks/OpenGL.framework/Versions/A/Resources/GLEngine.bundle/GLEngine (unknown line)
glDrawElements_GL3Exec at /System/Library/Frameworks/OpenGL.framework/Versions/A/Resources/GLEngine.bundle/GLEngine (unknown line)
glDrawElements at /Users/benoitpasquier/.julia/packages/ModernGL/BUvna/src/functionloading.jl:73 [inlined]
render at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/GLAbstraction/GLRender.jl:132
jfptr_render_60756 at /Users/benoitpasquier/.julia/compiled/v1.11/GLMakie/nfnZR_l4n56.dylib (unknown line)
StandardPostrender at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/GLAbstraction/GLRenderObject.jl:68
jfptr_StandardPostrender_65527 at /Users/benoitpasquier/.julia/compiled/v1.11/GLMakie/nfnZR_l4n56.dylib (unknown line)
render at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/GLAbstraction/GLRender.jl:92
jfptr_render_60825 at /Users/benoitpasquier/.julia/compiled/v1.11/GLMakie/nfnZR_l4n56.dylib (unknown line)
render at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/GLAbstraction/GLRender.jl:70
jfptr_render_60772 at /Users/benoitpasquier/.julia/compiled/v1.11/GLMakie/nfnZR_l4n56.dylib (unknown line)
render at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/rendering.jl:127
#render_frame#158 at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/rendering.jl:75
render_frame at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/rendering.jl:29 [inlined]
on_demand_renderloop at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/screen.jl:939
renderloop at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/screen.jl:963
jfptr_renderloop_61300 at /Users/benoitpasquier/.julia/compiled/v1.11/GLMakie/nfnZR_l4n56.dylib (unknown line)
#71 at /Users/benoitpasquier/.julia/packages/GLMakie/TH3rf/src/screen.jl:823
jfptr_YY.71_61597 at /Users/benoitpasquier/.julia/compiled/v1.11/GLMakie/nfnZR_l4n56.dylib (unknown line)
jl_apply at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZM05NJYVY.0/build/default-grannysmith-C07ZM05NJYVY-0/julialang/julia-release-1-dot-11/src/./julia.h:2157 [inlined]
start_task at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZM05NJYVY.0/build/default-grannysmith-C07ZM05NJYVY-0/julialang/julia-release-1-dot-11/src/task.c:1202
Allocations: 18659365 (Pool: 18649180; Big: 10185); GC: 15
Segmentation fault: 11 EDIT: I'll update GLMakie and try again. BTW unless it's just a coincidence, it seems I'm not the only one (just saw some similar segafault on the slack Makie channel). EDIT2: Yep, same segfault with GLMakie v0.11.2, Makie v0.22.1. julia> versioninfo()
Julia Version 1.11.3
Commit d63adeda50d (2025-01-21 19:42 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: macOS (x86_64-apple-darwin24.0.0)
CPU: 12 × Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
WORD_SIZE: 64
LLVM: libLLVM-16.0.6 (ORCJIT, skylake)
Threads: 1 default, 0 interactive, 1 GC (on 12 virtual cores) |
Huh, looks like segfaults moved from m1 (I used to see a bunch, but not in the same place that you are seeing them and not anymore) on to Intel :D . @briochemc I would move to WGLMakie or CairoMakie for now - for this kind of diagram, it won't make a difference. |
I'll admit I don't really understand the arrows yet, but testing with some other data taken from that python example I get the right locations of the dots:
code (not cleaned up): # Taylor plot
using CairoMakie
using Statistics
# 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
# INPUT
# sdmod_rel = [0.8,1.2]
sdmod_rel = [std(data) ./ std(obs_data) for data in model_data]
# sdmod_rel = [std(data) for data in model_data]
# correl = [0.8, 0.5]
correl = [cor(data, obs_data) for data in model_data]
bias = 0.3
sd_obs = 1.0
plot_bias = false
plot_variance_error = false
# Do the actual plotting now
# First, construct the figure and a polar axis on the first quadrant
fig = Figure(size=(400, 400))
# Corrticks for Taylor diagram
# corrticks = [-1; -0.99; -0.95; -0.9:0.1:0.9; 0.95; 0.99; 1.0]
# corrminorticks = [-1; -0.99:0.01:-0.9; 0.85:0.05:0.85; 0.9:0.01:0.99; 1.0]
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]
# corrminorticks = [-1; -0.99:0.01:-0.9; 0.85:0.05:0.85; 0.9:0.01:0.99; 1.0]
# thetaticks for taylor diagram
thetaticks = (acos.(corrticks), string.(corrticks))
# thetaminorticks = acos.(corrminorticks)
rlimits = (0, 2.7)
ax = PolarAxis(fig[1, 1];
thetalimits = (0, π), # first quadrant only
thetagridcolor = (:black, 0.5),
thetagridstyle = :dot,
thetaticks,
# thetaminorticks,
rlimits,
rgridcolor = cgrad(:Archambault, categorical = true)[1],
rticklabelcolor = cgrad(:Archambault, categorical = true)[1],
rgridstyle = :dash,
rticks = -2.5:0.5:2.5,
)
# # ax.thetalimits[] = (0, pi/2) # first quadrant only
# ax.thetalimits[] = (0, pi) # first quadrant only
# # Now, style the axis appropriately for a Taylor plot
# ax.thetagridcolor = (:black, 0.1)
# ax.thetagridstyle = :dash
# Now, go forth and plot!
# First, plot the grid lines for the correlation
# TODO: it would be better if we had labelled lines
# plucked from the contour recipe,
# but since we don't, we can do this manually.
"A transformation function that goes from correlation and standard deviation to the Taylor plot's Cartesian space."
correl_sd2taylor_transf = Makie.PointTrans{2}() do (correl, sd)
Point2(correl * sd, sqrt(sd^2-(correl*sd)^2)) * sd_obs
end
correl_sd2taylor(sd, correl) = (x=correl * sd, y=sqrt(sd^2-(correl*sd)^2))
# Create Taylorplot gridlines
# sdmax = max(maximum(sdmod_rel), 1.0)
sdmax = 2rlimits[2]
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
# Create isolines of root mean squared difference (RMSD) and labels
# RMSD = 0.2:0.2:2*sdmax+0.2
RMSD = 0.5:0.5:2*sdmax+0.5
xvec = -1.0:0.01:1
for r in RMSD[1:end-1]
# this is slightly different from the "true transform"
# so we compute the points directly and plot in corrected space
points = @. Point2f((xvec * r + 1) * sd_obs, sqrt(1-xvec^2) * r * sd_obs)
points_inds = splat(hypot).(points) .<= 1.005 * (maximum(sds)) * sd_obs
lines!(ax,
points[points_inds];
# color=(:black, 0.5),
color = cgrad(:Archambault, categorical = true)[3],
linewidth = 1,
transformation = Transformation(ax.scene.transformation; transform_func = identity),
xautolimits = false,
yautolimits = false,
# label = "RMSD $r"
) # each line gets a label, so they should be separate
end
# Now, plot the actual data
# First the arrows
xy_orig = Point2f.(sdmod_rel, correl)
x,y = collect.(zip(correl_sd2taylor.(sdmod_rel, correl)...) |> collect) .* sd_obs
xy = Point2f.(x,y)
scatter!(ax, x, y;
color = [:red, :green],
marker = [:cross, :star5],
transformation = Transformation(ax.scene.transformation; transform_func = identity)
)
scatter!(ax, [1], [0];
color = :black,
transformation = Transformation(ax.scene.transformation; transform_func = identity)
)
if plot_bias
# here we want to be in Cartesian space, since we're calculating angles
RMSD = @. sqrt(sd_obs^2 + (sdmod_rel*sd_obs)^2 - 2*sd_obs^2*sdmod_rel*correl)
RMSE = @. sqrt(bias^2+RMSD^2)
RMSDangle = @. atan(y/RMSD)
RMSEangle = @. atan(bias/RMSE)
alpha = @. ifelse(x > sd_obs, π - RMSDangle - RMSEangle, RMSDangle - RMSEangle)
xb = @. sd_obs - cos(alpha)* RMSE
yb = @. sin(alpha) * RMSE
arrows!(ax, x, y, xb.-x, yb.-y; color=1:length(x), linewidth=3, transformation = Transformation(ax.scene.transformation; transform_func = identity))
end
if plot_variance_error
# this should also be in Cartesian space because the vector subtraction has to happen there.
xy_no_var_err = Point2f.(1.0, correl)
xy_no_var_err = Makie.apply_transform(correl_sd2taylor_transf, xy_no_var_err)
arrows!(ax, xy, xy_no_var_err .- xy; color=1:length(xy), linewidth=3, transformation = Transformation(ax.scene.transformation; transform_func = identity))
end
fig EDIT: Actually maybe it's a bit off 🤔 |
|
I ended up baking my own based on your code @asinghvi17 (but I used ![]() # 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
Ē = f̄ - r̄
# Centered Root Mean Square Difference
E′ = sqrt(mean(((f .- f̄) - (r .- r̄)) .^ 2, args...))
# Full Mean Square Difference
E² = E′^2 + Ē^2
# Normalized values (maybe that needs to be a kwarg)
Ê′ = E′ / σr
σ̂f = σf / σr
σ̂r = 1.0
return (; σr, σf, R, 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 Note that I used the original paper's notation for clarity. I also left some args... in there because I could use some weights as well. Also note that my correlation tick labels could be improved with a proper minus sign. But overall I'm pretty happy with that and it's not much code TBH. The only thing I would like is ticks (#4773) and axis labels (#4076). |
Can anyone make a simple 2-5 line MWE, so we can investigate the segfault? |
@SimonDanisch For me this minimal example: using GLMakie
fig, ax, plt = lines(Point{2, Float32}[[-1.2, 0.0]]) throws this segfault:
Some setup details: (@v1.11) pkg> st -m GLMakie Makie
Status `~/.julia/environments/v1.11/Manifest.toml`
[e9467ef8] GLMakie v0.11.2
[ee78f7c6] Makie v0.22.1
julia> versioninfo()
Julia Version 1.11.3
Commit d63adeda50d (2025-01-21 19:42 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: macOS (x86_64-apple-darwin24.0.0)
CPU: 12 × Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
WORD_SIZE: 64
LLVM: libLLVM-16.0.6 (ORCJIT, skylake)
Threads: 1 default, 0 interactive, 1 GC (on 12 virtual cores) |
Feature description
I would like to kindly request a Taylor diagram recipe!
For plot types, please add an image of how it should look like
Given some model data and observed (true) data, it should return a plot that looks like this (copied from the wikipedia article):
These diagrams are useful for plotting the "skill" of a model, and are used a fair bit in climate / ocean / atmospheric sciences. AFAIK, the original paper is openly accessible at https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2000JD900719.
FWIW, there is a 2-year-old Discourse comment by @mreichMPI-BGC with an implementation, but when I tried it, it threw some errors, and after applying some quick bandaid (code below), it threw a segfault for me...
The text was updated successfully, but these errors were encountered: