# Makie: open-ended contouring levels for contourf?

**URL:** <https://discourse.julialang.org/t/makie-open-ended-contouring-levels-for-contourf/106411>\
**Category:** Visualization\
**Tags:** question, makie, contouring\
**Created:** [November 18, 2023, 4:25pm UTC](https://discourse.julialang.org/t/makie-open-ended-contouring-levels-for-contourf/106411 "2023-11-18T16:25:42Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [November 18, 2023, 4:25pm UTC](https://discourse.julialang.org/t/makie-open-ended-contouring-levels-for-contourf/106411/1 "2023-11-18T16:25:42Z")

</div>

[This thread](https://discourse.julialang.org/t/cairomakie-contourf-set-colour-limits/79261) 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](https://docs.makie.org/stable/reference/blocks/colorbar/) 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.

 ![tmp](https://global.discourse-cdn.com/julialang/original/3X/f/3/f38f80874d3b0b9f3d89b00171a86571cce7f05d.png)  
 ![tmp2](https://global.discourse-cdn.com/julialang/original/3X/3/7/37c9b60bf5405c5fb4920273e2b28fa6b1830d5f.png)

```julia
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])
tightlimits!(ax)
c = contourf!(ax, xs, ys, arr; levels=-0.5:0.1:0.5)
Colorbar(fig[1,2], c)
save("tmp2.png", fig)

```

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [November 18, 2023, 4:45pm UTC](https://discourse.julialang.org/t/makie-open-ended-contouring-levels-for-contourf/106411/2 "2023-11-18T16:45:53Z")

</div>

This is called `extendlow` and `extendhigh` for `contourf` [contourf · Makie](https://docs.makie.org/dev/reference/plots/contourf/index.html). 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.

---

<div class="post-metadata">

**Author:** ![ryofurue](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ryofurue/32/24531_2.png) [@ryofurue](https://discourse.julialang.org/u/ryofurue)\
**Post date:** [November 23, 2023, 3:03am UTC](https://discourse.julialang.org/t/makie-open-ended-contouring-levels-for-contourf/106411/3 "2023-11-23T03:03:19Z")

</div>

> [@jules](#):
>
> This is called `extendlow` and `extendhigh` for `contourf` [contourf · Makie](https://docs.makie.org/dev/reference/plots/contourf/index.html). 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.

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:

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

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:

```julia
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`.
