Hi @sylvaticus , this is what I did using Makie.jl (and using also @rafael.guerra’s justifyme()
function. It can be refined and a recipe would be better, but had no time to study how to.
using CairoMakie, Colors, Random
# For horizintal and vertical text alignment:
justifyme(θ) = (0≤θ<π/2 || 3π/2<θ≤2π) ? :left : (π/2<θ<3π/2) ? :right : :center
justifymeV(θ) = π/4≤θ≤3π/4 ? :bottom : 5π/4<θ≤7π/4 ? :top : :center
# Radar plot function:
function radarplot(ax::Axis, v; p_grid = maximum(v) * (1.0:5.0) / 5.0, title = "", labels = eachindex(v), labelsize = 1, points=true, spokeswidth= 1.5, spokescolor=:salmon, fillalpha=0.2, linewidth=1.5)
# Axis attributes
ax.xgridvisible = false
ax.ygridvisible = false
ax.xminorgridvisible = false
ax.yminorgridvisible = false
ax.leftspinevisible = false
ax.rightspinevisible = false
ax.bottomspinevisible = false
ax.topspinevisible = false
ax.xminorticksvisible = false
ax.yminorticksvisible = false
ax.xticksvisible = false
ax.yticksvisible = false
ax.xticklabelsvisible = false
ax.yticklabelsvisible = false
ax.aspect = DataAspect()
ax.title = title
#
l = length(v)
rad = (0:(l-1)) * 2π / l
# Point coordinates
x = v .* cos.(rad)
y = v .* sin.(rad)
if p_grid != 0
# Coordinates for radial grid
xa = maximum(p_grid) * cos.(rad) * 1.1
ya = maximum(p_grid) * sin.(rad) * 1.1
# Coordinates for polar grid text
radC = (rad[Int(round(l / 2))] + rad[1 + Int(round(l / 2))]) / 2.0
xc = p_grid * cos(radC)
yc = p_grid * sin(radC)
for i in p_grid
poly!(ax, Circle(Point2f(0, 0), i), color = :transparent, strokewidth=1, strokecolor=ax.xgridcolor)
end
text!(ax, xc, yc, text=string.(p_grid), textsize = 12, align = (:center, :baseline), color=ax.xlabelcolor)
arrows!(ax, zeros(l), zeros(l), xa, ya, color=ax.xgridcolor, linestyle=:solid, arrowhead=' ')
if length(labels) == l
for i in eachindex(rad)
text!(ax, xa[i], ya[i], text=string(labels[i]), textsize = labelsize, markerspace = :data, align = (justifyme(rad[i]), justifymeV(rad[i])), color=ax.xlabelcolor)
end
elseif length(labels) > 1
printstyled("WARNING! Labels omitted: they don't match with the points ($(length(labels)) vs $l).\n", bold=true, color=:yellow)
end
end
pp = poly!(ax, [(x[i], y[i]) for i in eachindex(x)], strokecolor=RGB{Float32}(0.4, 0.4, 0.4))
cc = to_value(pp.color)
m_color = RGBA{Float32}(comp1(cc), comp2(cc), comp3(cc), fillalpha)
s_color = RGB{Float32}(comp1(cc), comp2(cc), comp3(cc))
pp.color = m_color
pp.strokecolor = s_color
pp.strokewidth= linewidth
arrows!(ax, zeros(l), zeros(l), x, y, color=spokescolor, linewidth=spokeswidth, arrowhead=' ')
if points
scatter!(ax, x, y)
end
ax
end
# INPUT DATA:
Random.seed!(1789)
n = 8
R1, R2 = rand(n), rand(n)
labels = "Cat." .* string.(1:n)
fig = Figure()
ax=Axis(fig[1,1])
radarplot(ax, R1; labels=labels, spokeswidth = 0, p_grid=0.2:0.2:1.0, labelsize=0.07)
radarplot(ax, R2; title="My Radar", labels="", spokeswidth = 0, p_grid=0)
What is inconvenient is the label size: in order to get them always displayed in the boundigbox, and not truncated, I had to specify the size in data space (markerspace = :data
), instead of in pixel space (which would allow to keep text size independent of data scaling; see documenatation page)