Makie - tricontourf from matplotlib in Makie

Hi everyone,
I am trying to get something like tricontourf from matplotlib to work in Makie. The heatmap with three vector inputs example here is the closest I can find in the documentation, but there’s no obvious way to get the spatial interpolation. Trying contourf with three input vectors fails, as it expects a matrix for the third. Has anyone implemented something like the tricontourf function from matplotlib in Makie?

Can you please provide an example of the expected output with tricontourf? Most of us here don’t have a Matlab license.

Hi, I think you misread. I am referring to the python package matplotlib, whose tricontourf can be seen here. There’s nothing about Matlab; I am not sure Matlab even has an analogous function (I certainly could not find it in the docs).

1 Like

I faced exactly this problem recently and cooked up a workaround involving Triangulate.jl and TriplotBase.jl

I’ll post more details later when I am back on my computer with the codes on it.

Thank you!

GMT’s contourf does exactly that.

Hi, is there some example code you could share that worked for you?

I am unfamiliar with GMT; is it built on top of Makie?

No.
The link I posted is from the GMT.jl manual

Sorry for the delay in providing the example. I somehow had trouble coloring the filled contours, but here goes:


#tricontour working example
using TriplotBase, Triangulate, GLMakie

function append_with_nan!(a,b)
    append!(a,b)
    push!(a,NaN)
end

conttype(contour::TriplotBase.Contour{T}) where {T} = T
#create some data
x = [0.0, 0.5, 1.0, 0.25, 0.75, 0.5]
y = sqrt(3)/2*[0.0, 0.0, 0.0, 0.5, 0.5, 1.0]
z = [0.0, 0.0, 0.0, 1.0, 0.75, 0.75]

#figure and axes
fighandle = Figure(resolution = (1100, 900))
ax1 = Axis3(fighandle[1, 1], aspect = (1, sqrt(3)/2, 1))
ax2 = Axis(fighandle[1, 2], aspect = AxisAspect(2/sqrt(3)))
ax3 = Axis(fighandle[1, 3], aspect = AxisAspect(2/sqrt(3)))

scatter!(ax1, x, y, z, markersize = 2000, color = :black)

#trianulate datapoints
triin=Triangulate.TriangulateIO()
triin.pointlist=[x'; y']
(triout, vorout) = triangulate("Q", triin)
trianglelist = triout.trianglelist

#contours
contours = TriplotBase.tricontour(x, y, z, trianglelist, 15)
filledcontours = TriplotBase.tricontourf(x, y, z, trianglelist, 15)

#plot the contours in ax2 (code adapted to Makie.jl from TriplotRecipes.jl (which is for Plots.jl))
for contour=contours
    T = conttype(contour)
    xs = T[]
    ys = T[]
    zs = T[]
    for polyline=contour.polylines
        append_with_nan!(xs,first.(polyline))
        append_with_nan!(ys,last.(polyline))
        append!(zs,fill(contour.level,length(polyline)))
    end
    if !isempty(zs)
        lines!(ax2, xs, ys, color = zs, colorrange = (0.0, 1.0))
    end
end

#plot the filled contours in ax3 (code adapted to Makie.jl from TriplotGR.jl)


for filledcontour = filledcontours
    for polyline=filledcontour.polylines
        points = similar(polyline, Point2f) #this is probably horrible Julia, but it works for now.
        for i in axes(polyline)
            points[i] = polyline[i]
        end
        poly!(ax3, points)
    end
end

Currently produces this plot:

I somehow have trouble getting Makie.jl accept the “color” argument for poly! right now…so currently the righthand figure just cycles through the color…

But, it’s pretty close?

Can you open an issue with a minimal reproducable example?

I’ll try :slight_smile:

I did some further work on this to be clear about what I tried. Maybe I just didn’t do it right - happy to be enlightened!

As agreed, I posted this also as an issue to Makie:

using TriplotBase, Triangulate, GLMakie, ColorSchemes

function append_with_nan!(a,b)
    append!(a,b)
    push!(a,NaN)
end

conttype(contour::TriplotBase.Contour{T}) where {T} = T
#create some data
x = [0.0, 0.5, 1.0, 0.25, 0.75, 0.5]
y = sqrt(3)/2*[0.0, 0.0, 0.0, 0.5, 0.5, 1.0]
z = [0.0, 0.0, 0.0, 1.0, 0.75, 0.75]

#figure and axes
fighandle = Figure(resolution = (900, 900))
ax2 = Axis(fighandle[1, 1], aspect = AxisAspect(2/sqrt(3)))
ax3 = Axis(fighandle[1, 2], aspect = AxisAspect(2/sqrt(3)))
ax4 = Axis(fighandle[2, 1], aspect = AxisAspect(2/sqrt(3)))
ax5 = Axis(fighandle[2, 2], aspect = AxisAspect(2/sqrt(3)))

#trianulate datapoints
triin=Triangulate.TriangulateIO()
triin.pointlist=[x'; y']
(triout, vorout) = triangulate("Q", triin)
trianglelist = triout.trianglelist

#contours
contours = TriplotBase.tricontour(x, y, z, trianglelist, 15)
filledcontours = TriplotBase.tricontourf(x, y, z, trianglelist, 15)

#plot the contours in ax2 (code adapted to Makie.jl from TriplotRecipes.jl (which is for Plots.jl))
for contour=contours
    T = conttype(contour)
    xs = T[]
    ys = T[]
    zs = T[]
    for polyline=contour.polylines
        append_with_nan!(xs,first.(polyline))
        append_with_nan!(ys,last.(polyline))
        append!(zs,fill(contour.level,length(polyline)))
    end
    if !isempty(zs)
        lines!(ax2, xs, ys, color = zs, colorrange = (0.0, 1.0), colormap = :magma)
    end
end

#try getting filled contours into ax3 (code adapted to Makie.jl from TriplotGR.jl) - works, but just with cycled colors.
for filledcontour = filledcontours
    for polyline=filledcontour.polylines
        points = similar(polyline, Point2f) #this is probably horrible Julia, but it works for now.
        for i in axes(polyline)
            points[i] = polyline[i]
        end
        poly!(ax3, points)
    end
end

#try getting filled contours into ax4 (code adapted to Makie.jl from TriplotGR.jl) - try coloring contours properly by specifying color, colorrange and colormap.
#--> results in an empty plot
lmin,lmax = extrema(getfield.(filledcontours,:lower))
for filledcontour = filledcontours
    for polyline=filledcontour.polylines
        points = similar(polyline, Point2f) #this is probably horrible Julia, but it works for now.
        for i in axes(polyline)
            points[i] = polyline[i]
        end
        poly!(ax4, points, color = filledcontour.lower, colorrange = (lmin, lmax), colormap = :magma)
    end
end

#try getting filled contours into ax5 (code adapted to Makie.jl from TriplotGR.jl) - try coloring contours by specifying colors directly
#--> results in just one contour shown with one color - why?
colors = colorschemes[:magma]
lmin,lmax = extrema(getfield.(filledcontours,:lower))
for filledcontour = filledcontours
    for polyline=filledcontour.polylines
        points = similar(polyline, Point2f) #this is probably horrible Julia, but it works for now.
        for i in axes(polyline)
            points[i] = polyline[i]
        end
        poly!(ax5, points, color = colors[div(255*filledcontour.lower-lmin,lmax-lmin)+1])
    end
end

Resulting plot:

I’ve started to turn this approach into a PR here Tricontourf plot by jkrumbiegel · Pull Request #2226 · JuliaPlots/Makie.jl · GitHub