I’m trying to generate a heatmap to visualize the output of a function evaluated on a grid of points over the unit 2-simplex. Here’s an example of the sort of data I’m working with:
using Plots, Combinatorics, StatsBase
function simplex_grid(num_outcomes, points_per_dim)
num_points = multinomial(num_outcomes-1, points_per_dim)
points = Array{Float64,2}(undef, num_outcomes, num_points)
for (p,comb) in enumerate(with_replacement_combinations(1:num_outcomes, points_per_dim))
distr = counts(comb, 1:num_outcomes) ./ points_per_dim
points[:,p] = distr
end
return points
end
function bary2cart(points)
x = (2 .* points[3,:] .+ points[1,:]) ./ dropdims(sum(points, dims=1), dims=1) ./ 2
y = √3 / 2 .* points[1,:] ./ dropdims(sum(points, dims=1), dims=1);
return (x,y)
end
points_per_dim = 30
num_outcomes = 3
grid = simplex_grid(num_outcomes, points_per_dim)
(x,y) = bary2cart(grid)
z = rand(length(x))
The best solutions I’ve come up with so far are 1) a scatter plot with hexagonal markers:
plot(showaxis=false, grid=false, ticks=false, xlims=(-.08,1.08), ylims=(-.08,.√.75+.08))
scatter!(x,y, zcolor=z, markerstrokewidth=0, markershape=:hexagon, markersize=8, label="")
plot!([0,.5,1,0],[0,√.75,0,0], color=:black, markeralpha=0, label="")
annotate!(.5, √.75+.07, text("A", 12))
annotate!(-.05, -.05, text("B", 12))
annotate!(1.05,-.05, text("C", 12))
or 2) a surface with the camera directly above:
plot(showaxis=false, grid=false, ticks=false, xlims=(-.08,1.08), ylims=(-.08,.√.75+.08))
surface!(x,y,z, zcolor=z, camera=(0,90))
plot!([0,.5,1,0],[0,√.75,0,0], color=:black, markeralpha=0, label="")
But both of these have significant drawbacks. The hexagons tend to have gaps or overlaps, and don’t allow any interpolation. The surface doesn’t allow annotations, and has weirdly jagged edges. Any suggestions for how to improve on (or replace) either of these would be appreciated!
Related but less important: I also tried plotting the barycentric coordinates directly, but couldn’t figure out how to get the view aligned orthogonal to the plane of the simplex. Is there anywhere I can find a basic explanation of how the “camera” keyword works?