Makie: open-ended contouring levels for contourf?

This thread discusses how to limit the contouring values. My question is a followup on that: How to paint all values above and below the limits and coordinate with the colorbar?

The first image below is what I need and the second image is what my little Julia program (shown at the very end) produces. Please focus on the colorbar of the first image: the (-Inf, -0.5) range is painted in the lowest extreme color of viridis and the (0.5, Inf) range is painted in the highest extreme color, and the colorbar has little triangles at the ends.

The Makie:Colorbar tutorial shows how to use lowclip and highclip, so there is a great hope, but I don’t know how to limit the color range of the palette (viridis, in the present case) and reserve the highest and lowest extreme colors for the triangles. (Okay, I could create my own version of viridis removing the extremities and use them for the lowclip and highclip colors, but that would be super tedious . . .)

In any case, this kind of open-ended contouring is so common (at least in my field) that it would be nice if there be a half-automatic solution.

I’ve tried levels = vcat(-Inf, -0.5:0.1:0.5, Inf), which I thought would be an obvious solution but which resulted in error.

using CairoMakie

func(x,y) = cos(2Ď€*x/100) * sin(2Ď€*y/100)

xs = 0:10:100
ys = 0:10:100
arr = func.(xs, reshape(ys,1,:))

fig = Figure()
ax = Axis(fig[1,1])
c = contourf!(ax, xs, ys, arr; levels=-0.5:0.1:0.5)
Colorbar(fig[1,2], c)
save("tmp2.png", fig)

This is called extendlow and extendhigh for contourf contourf · Makie. I didn’t call it highclip and lowclip precisely because you take a chunk out of the colorbar basically, which doesn’t happen for the continuous variants you find in heatmap etc.

1 Like

Thank you!!!

First, I should’ve looked at the manual of contourf before resorting to search. Sorry for not having done my homework properly.

Also, I wonder whether it would make sense

  1. to enable encoding extend??? in contour levels. For example, levels=vcat(-Inf, -10:1:10) would imply levels=-10:1:10, extendlow=:auto . . . ? Or

  2. to introduce a “levels object”, something that behaves like levs = (levels = -10:1:10, extendlow = :auto) . . . ?

My current solution is to simulate 2 above:

function myplot( . . . ; levs = ()) # defaulting to an empty tuple
  # . . . 
  contourf( . . . ; levs...)
  # . . .

levs = if (somecond) ? (levels=-10:1:10, extendlow = :auto) : (levels = -1:0.1:1)
myplot(. . . ; levs = levs)

This isn’t too bad at all. It’s more general, too; that is, to bundle any attributes together as you like. I just thought that extend??? and levels combined conceptually form a single object in the user’s mind.

Off topic: I’m finding that Makie doesn’t seem to have a unified “undefined” value for attributes, which confuses me a lot:

function myplot(. . . ; axislabel = nothing)
  fig = Figure()
  ax = Axis(fig[1,1]; ylabel = axislabel) # <- does this work?

For String attributes, it seems that the empty string "" acts as “undefined” but I don’t know if that’s really the case for all string attributes.

What about other attributes? Both levels=nothing and levels=:auto result in error, for example.

I wish that attributeX = nothing were always equivalent to “not specifying attributeX”. Currently, all I can think of is to use the named-tuple-splattering trick I show above in order to simulate nothing.