If the input data is a sparse grid instead of a function evaluated on a dense grid, the nice solution above using NaNs may leak:
Here below another approach using Dierckx.jl to interpolate a bounding polygon (and respective values) which is then merged with the input data and fed to PyPlot.jl’s tricontour()
.
The main advantages of this workflow is that irregular input data can be consumed and “arbitrary” polygons can be defined.
PS: Someone versed in PyPlot, may step-in with further advice.
using Dierckx, PyPlot
# Define some input data inside a triangle
f(x,y) = cos(2π*x) * sin(2π*y)
Np = 2_000; x = zeros(Np); y = zeros(Np)
for i in 1:Np
x[i] = rand(0:0.01:1); y[i] = rand(0:0.01:1-x[i])
end
z = f.(x,y)
# define bounding polygon vertices for contouring (here a triangle)
polygon = [0. 0.; 1. 0.; 0. 1.; 0. 0.] # closed triangle (4 points)
N = size(polygon,1)
# Interpolate polygon border using linear parametric splines, and respective values using cubic
t = collect(1:N)
spl1 = ParametricSpline(t, polygon', k=1) # linear splines
tfine = LinRange(0, N, 1000) # polygon boundary samples = 1000
xypoly1 = evaluate(spl1,tfine) # 2 x 1000 matrix
spl2 = Spline2D(x, y, z; kx=3, ky=3, s=1e-4)
zpoly2 = evaluate(spl2, xypoly1[1,:], xypoly1[2,:]) # cubic splines
# merge input data with polygon boundary
xnew = [x; xypoly1[1,:]]
ynew = [y; xypoly1[2,:]]
znew = [z; zpoly2]
xyz = [xnew ynew znew]
xyz = unique(xyz, dims= 1) # keep only unique points
# plot the data support and filled contours
clf()
PyPlot.scatter(x,y,s=0.1)
plt.plot(xypoly1[1,:],xypoly1[2,:], c="red", lw=1)
clf()
PyPlot.tricontourf(xyz[:,1], xyz[:,2], xyz[:,3])
PyPlot.colorbar()
PyPlot.tricontour(xyz[:,1], xyz[:,2], xyz[:,3], colors="black", linewidths=0.5)