# Makie observable lift functions

**URL:** https://discourse.julialang.org/t/makie-observable-lift-functions/121202
**Category:** Visualization
**Tags:** makie, observables
**Created:** [October 11, 2024, 5:47pm UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202 "2024-10-11T17:47:11Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![Andy2K11](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andy2k11/32/9967_2.png) [@Andy2K11](https://discourse.julialang.org/u/Andy2K11)
#### Post date: [October 11, 2024, 5:47pm UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202/1 "2024-10-11T17:47:11Z")

</div>

Hi. I’ve been trying to learn how to use observables in Makie and have managed to make an interactive plot with an IntervalSlider.

The xaxis ticks are controlled with a `lift` function:

```julia
xticks = lift(ab_slider.interval) do val
    collect(val), ["a", "b"]
end

```

Now that works, I would like to make it so that if a \leq 0 the left tick is displayed as `0` instead of `a`. Similarly for the upper bound, b would be replaced with the max xaxis limit.

I started with some `if else` statements in my function, and while it runs, the IntervalSlider and plot become really unresponsive.

```julia
xticks = lift(ab_slider.interval) do val
    if val[1] > 0 && val[2] < 4
        return collect(val), ["a", "b"]
    else
        return [0, 4], ["0", "4"]
    end
end

```

Not only does the UI seem a bit unresponsive, but sometimes the tick values don’t update at all, and other times something seems to trigger them but not always. I suspect that I’ve not understood something about how Observables work. I found working with an observable of a tuple value for the interval less than intuitive. Thanks.

---

<div class="post-metadata">

### Author: ![contradict](https://avatars.discourse-cdn.com/v4/letter/c/ac91a4/32.png) [@contradict](https://discourse.julialang.org/u/contradict)
#### Post date: [October 11, 2024, 8:41pm UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202/2 "2024-10-11T20:41:15Z")

</div>

This probably is not all of the problem, but that logic looks wrong. If either limit is reached, the fixed ends are used. Try this:

```julia
xticks = lift(ab_slider.interval) do val
    clamp.(val, 0, 4), ["a", "b"]
end

```

---

<div class="post-metadata">

### Author: ![Andy2K11](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andy2k11/32/9967_2.png) [@Andy2K11](https://discourse.julialang.org/u/Andy2K11)
#### Post date: [October 11, 2024, 9:23pm UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202/3 "2024-10-11T21:23:46Z")

</div>

> [@contradict](#):
>
> `clamp.(val, 0, 4), ["a", "b"]`

The logic isn’t fully implemented in my example as I wanted to keep it simple and what I put was enough to reproduce the problem.

Another side issue, is that if the value of a = 0 and I want to have `["0", "a", "b", "4"]` as my ticks, then I get a `zero step` error. So I do need to implement logic to prevent this happening, but any form of logic makes the UI unresponsive and glitchy in terms of updating.

I wondered if it had something to do with the way the `Observable` wraps a tuple value, and I’m looking for changes in the individual values?

---

<div class="post-metadata">

### Author: ![contradict](https://avatars.discourse-cdn.com/v4/letter/c/ac91a4/32.png) [@contradict](https://discourse.julialang.org/u/contradict)
#### Post date: [October 11, 2024, 9:35pm UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202/4 "2024-10-11T21:35:54Z")

</div>

Can you share a runnable example that exhibits the problem? I haven’t had problems putting complicated data types in Observables before, but that might have something to do with it.

---

<div class="post-metadata">

### Author: ![Andy2K11](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andy2k11/32/9967_2.png) [@Andy2K11](https://discourse.julialang.org/u/Andy2K11)
#### Post date: [October 11, 2024, 10:21pm UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202/5 "2024-10-11T22:21:52Z")

</div>

I think I’ve fixed it.

When I tried making up a full minimal example I decided to do it in a single script file instead of a jupyter notebook. Then I noticed lots of runtime errors appearing in the console that I hadn’t seen before.

The error was an `inexact error` and all I had to do was change the integers to floats. This error was only occurring when the conditional logic kicked in.

Thanks for your help.

Edit: I’ll just throw this in as an example for anyone else who wants to do the same

```julia
using GLMakie
GLMakie.activate!(; float=true)
set_theme!(theme_black())

##

f(x) = exp(-x/2)
xs = LinRange(0, 4, 41)

fig = Figure(size=(800, 600))

ab_slider = IntervalSlider(fig[2, 1], range = 0:0.1:4, startvalues = (0.0, 4.0))

xticks = lift(ab_slider.interval) do val
    if val[1] > 0.0 && val[2] < 4.0
        return collect(val), ["a", "b"]
    else
        return [0.0, 4.0], ["0", "4"] # Needs to be 4.0 and not 4
    end
end

ax = Axis(fig[1, 1], xticks=xticks)
lines!(ax, xs, f)

fig

```

It’s a bit weird that only the second value in the return array needed to be a float to avoid the error.

Edit 2: It can be either 0.0 or 4.0, just not both integers 0 and 4. Sure there’s some reason behind it somewhere. Edit 3: Ah, it must make the xticks float if either value is set as float, and then it’s ok.

---

<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: [October 12, 2024, 6:37am UTC](https://discourse.julialang.org/t/makie-observable-lift-functions/121202/6 "2024-10-12T06:37:57Z")

</div>

With `lift` you need to be careful that the return type of your first invocation also works for all other possible branches because that’s the type parameter that the observable uses. So if you first return an integer and later a float, the float will fail to convert to an integer.

Sometimes you have a union of types like `Union{Nothing, Float64}`, in that case I usually create an empty observable first with the correct type parameter like `result = Observable{Union{Nothing, Float64}}` and then use the `map!` function on that with the logic you’d otherwise put into `lift`
