# Real time plotting (with Makie)

**URL:** https://discourse.julialang.org/t/real-time-plotting-with-makie/20432
**Category:** Visualization
**Tags:** question
**Created:** [February 4, 2019, 4:10pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432 "2019-02-04T16:10:20Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![cserteGT3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csertegt3/32/8283_2.png) [@cserteGT3](https://discourse.julialang.org/u/cserteGT3)
#### Post date: [February 4, 2019, 4:10pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/1 "2019-02-04T16:10:20Z")

</div>

Currently I’m trying to plot real-time measured values (force values from a robot controller). By real-time I mean, at a 125Hz frequency as the values arrive. I’m working with Makie and concluded to this [code](https://gist.github.com/cserteGT3/4ebe5df6ade2bc6183f47b1bbbedc080) based on this [issue](https://github.com/JuliaPlots/Makie.jl/issues/279).  
I will just comment the above code:  
I got the values over TCP as a string in a format of `"[1.1, 2.2, 3.3, 4.4, 5.5, 6.6]\n"`.  
Then I update a string `Node` to process it with `readdlm()`. Right after processing I push the new values into a “fix size” array. This function is used to make the “fix size behaviour”:

```julia
function pushTo!(A, newX, maxSize)
    if size(A, 1) < maxSize
        push!(A, newX)
    else
        popfirst!(A)
        push!(A, newX)
    end
end

```

After updating the arrays I use the `lastUpdate` node to update the plot. I throttle it down:

```julia
        if (current_time-lastUpdate[])/1000000 > UPDATE_LAT
            lastUpdate[] = current_time
        end

```

where `UPDATE_LAT` is around 200 miliseconds. If that time is up, the next function is called to update the plot:

```julia
function updatePlot(val)
    fxNode[] = FxV
    fyNode[] = FyV
    fzNode[] = FzV
    txNode[] = TxV
    tyNode[] = TyV
    tzNode[] = TzV
    # update limits:
    for i in 1:6
        AbstractPlotting.update_limits!(sArr[i])
    end
    AbstractPlotting.update!(scene)
end

```

Here’s an example picture what I’ve created (with some random noise):

 ![plot2](https://global.discourse-cdn.com/julialang/original/3X/7/c/7c7d9a0aa1b4aa90a42ac4c95cd3d1dd7afd534f.png)

I tried to lower the `UPDATE_LAT` value to like 100 ms, but then plotting freezes out.  
Overall I’m happy that it works, but could it be improved? And is this the way to do this kind of plotting, or should I do something completely different?

Some version infos:

```julia
julia> versioninfo()
Julia Version 1.0.2
Commit d789231e99 (2018-11-08 20:11 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-3632QM CPU @ 2.20GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, ivybridge)
Environment:
  JULIA_EDITOR = "C:\Users\cstamas\AppData\Local\atom\app-1.34.0\atom.exe" -a
  JULIA_NUM_THREADS = 4

(julia-RTPlot) pkg> st
    Status `C:\Users\cstamas\Documents\Coding\julia-RTPlot\Project.toml`
  [537997a7] AbstractPlotting v0.9.4 #master (https://github.com/JuliaPlots/AbstractPlotting.jl.git) [6e4b80f9] BenchmarkTools v0.4.2
  [5789e2e9] FileIO v1.0.5
  [e9467ef8] GLMakie v0.0.4 #master (https://github.com/JuliaPlots/GLMakie.jl.git)
  [ee78f7c6] Makie v0.9.1 #master (https://github.com/JuliaPlots/Makie.jl.git)
  [510215fc] Observables v0.2.3

```

(I feel this post a bit unnecessary as my code is working, but I’m curious, if I made some mistake and/or how could I improve it.)

---

<div class="post-metadata">

### Author: ![asinghvi17](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/asinghvi17/32/8272_2.png) [@asinghvi17](https://discourse.julialang.org/u/asinghvi17)
#### Post date: [May 30, 2019, 6:06am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/2 "2019-05-30T06:06:39Z")

</div>

One thing you _could_ do to optimize drawing is to initially define a very large timescale, and then plot on that. This will avoid the `update_limits!`, which causes the plot to be redrawn.

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [May 30, 2019, 2:38pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/3 "2019-05-30T14:38:03Z")

</div>

Could you paste a complete working example (e.g. with random data)? I can take a look at it!

---

<div class="post-metadata">

### Author: ![cserteGT3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csertegt3/32/8283_2.png) [@cserteGT3](https://discourse.julialang.org/u/cserteGT3)
#### Post date: [June 3, 2019, 11:22am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/4 "2019-06-03T11:22:22Z")

</div>

[Here](https://github.com/cserteGT3/RealtimeplotExample) I created a working example. There’s also a longer description to describe the problem and the solution. The code is more or less commented. (I tested it only on windows, but I don’t think that anything that I use is platform dependent.)  
I have two concerns (besides that I don’t know if my approach is good):

- Almost everywhere I use global variables, which I find fragile (and the only way I know to do this).
- Don’t know if I should use other datastructure (for example [CircularBuffer](http://juliacollections.github.io/DataStructures.jl/latest/circ_buffer.html)).

I would be pleased, if you could review it.

---

<div class="post-metadata">

### Author: ![cserteGT3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csertegt3/32/8283_2.png) [@cserteGT3](https://discourse.julialang.org/u/cserteGT3)
#### Post date: [June 3, 2019, 11:24am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/5 "2019-06-03T11:24:33Z")

</div>

> This will avoid the `update_limits!` , which causes the plot to be redrawn.

I think I need the call `update_limits!`, because it’s possible that the (y) values are outside of the current range. The x range is fixed. (I also updated the code since the original post).

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [June 3, 2019, 12:03pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/6 "2019-06-03T12:03:56Z")

</div>

> [@cserteGT3](#):
>
> This will avoid the `update_limits!` , which causes the plot to be redrawn.

That’s not true… `update_limits` just causes the scene graph to get layouted, it has nothing to do with drawing the plot! Depending on your scene, `update_limit!` might still be the bottleneck though, since drawing is usually very fast.

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [June 3, 2019, 12:07pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/7 "2019-06-03T12:07:37Z")

</div>

That looks a bit like you turned your initial example into the opposite of a minimal example 😃  
Do you also have something that shows the gist of your plotting code in one file with only a couple of lines? Your initial code looked like that, but was incomplete.

---

<div class="post-metadata">

### Author: ![cserteGT3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csertegt3/32/8283_2.png) [@cserteGT3](https://discourse.julialang.org/u/cserteGT3)
#### Post date: [June 3, 2019, 12:46pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/8 "2019-06-03T12:46:26Z")

</div>

> [@sdanisch](#):
>
> That looks a bit like you turned your initial example into the opposite of a minimal example 😃

Yeah, it’s possible… 😃 I tried to give a working example, therefore I needed to implement the other side of the TCP connection too.

> [@sdanisch](#):
>
> Do you also have something that shows the gist of your plotting code in one file with only a couple of lines? Your initial code looked like that, but was incomplete.

Not sure how to compress it to a couple lines (I need to learn this too), tried to do it in this [gist](https://gist.github.com/cserteGT3/554c828e70ccd9758b11a3b591b4f4b8). It’s possible that it is still too verbose. 😃

---

<div class="post-metadata">

### Author: ![sdanisch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sdanisch/32/1406_2.png) [@sdanisch](https://discourse.julialang.org/u/sdanisch)
#### Post date: [June 3, 2019, 1:34pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/9 "2019-06-03T13:34:21Z")

</div>

That’s more like it - although it doesn’t run, so it’s still not a minimal working example (MWE)… Also, you could just use random data instead of including server code 😉

---

<div class="post-metadata">

### Author: ![cserteGT3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/csertegt3/32/8283_2.png) [@cserteGT3](https://discourse.julialang.org/u/cserteGT3)
#### Post date: [June 3, 2019, 2:17pm UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/10 "2019-06-03T14:17:11Z")

</div>

Yeah, I can do a working and a minimal example, but not a MWE.  
Here’s the next try [as gist](https://gist.github.com/cserteGT3/f3e6280e2625d799cfa61bf8c6e54197) and also an `src/mwe.jl` in the git repo.  
(It’s considered minimal as it implements the things I need: JSON parsing and buttons for pause/restart).  
`newvalues(number, sleep_time)` updates the `input_string` variable `number` times with `sleep(sleep_times)` between.

```julia
julia> include("src/mwe.jl")
0x000238a0fd5d4d40

julia> scene

julia> newvalues(1, 0.1)

julia> newvalues(100, 0.01)

```

---

<div class="post-metadata">

### Author: ![lwabeke](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lwabeke/32/4005_2.png) [@lwabeke](https://discourse.julialang.org/u/lwabeke)
#### Post date: [June 7, 2019, 8:02am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/11 "2019-06-07T08:02:07Z")

</div>

Maybe you need to start an approach of divide and conquer.  
Where is the real bottleneck?

- Check the parts that run at 125Hz first:
  - Are you happy that you can read from the socket and parse the JSON fast enough with no display?
  - Is the FIFO buffer mechanism your using able to run fast enough?

- If your sure it isn’t those aspects, then prototype the part running at the lower rate of 10-20Hz, i.e. the plotting part (or inter task issues, if your using separate tasks), in which can you can use a MWE which just plots random values, where you don’t need the JSON parsing etc., you probably don’t need buttons for this as well, it just needs to run for a minute, plotting at 10 frames a second. Heck in principle what your plotting should with proper GPU support be able to run at the 125Hz, consider people claim over 100 fps in games like quake (now I don’t say you need to aim for that rate, anything above 25 is unnecesary, since TVs ran in many parts of the world ran at 25Hz with no complains from viewers, and I would suggest from other scientific displays I have done in the past outside the Julia environment, that frame rates above 10Hz mostly becomes wasted).
- If your plotting MWE works good enough, it should just be a case of putting the parts together and making sure you don’t create some bottleneck in the way the parts work together.

In any case, I’m interested in following to here if there are other revelations, since in the near future I might also need to do something similar.

---

<div class="post-metadata">

### Author: ![wsphillips](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsphillips/32/6777_2.png) [@wsphillips](https://discourse.julialang.org/u/wsphillips)
#### Post date: [August 1, 2019, 11:32am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/12 "2019-08-01T11:32:18Z")

</div>

Hello,

I myself have been looking to acquire high frequency signals and display them with a good framerate. The MWE below runs with either static axes or “chart” style time scrolling. For simplicity I’m just filling up an array and using the system clock, but in practice data would come in chunks and plotting will be triggered by a hardware clock’s callback function (rather than the sleep timer)…

Anyhow: The bottom line is (in my hands) plotting via Observables is insanely quick, but if you want dynamic axes it really costs you. Granted there’s some overhead with timing but I am getting frame render times of ~0.1ms with static axes and 20ish ms with “updating”.

@sdanisch Is there a better way to handle this? I noticed the double updating I’ve used is also how you made the animation example in the Makie gallery. For most time signals you could get away with a static or “on event” scaling Y-axis and then a regularly changing X-axis. I’m guessing this could be much simpler and quicker than min maxing each frame???

MWE of faux streaming data w/Makie plots:

```julia
using Makie

scene = Scene()
data = Node(rand(1000))
t = lift(c -> length(c), data)
y = lift(a -> to_value(data)[max(1, a-999):max(a, 1000)], t)
#x = lift(b -> collect(max(b-999, 1):max(b, 1000)), t)
x = 1:1000 # for static axis
lines!(scene, x, y)

@time for i in 1:500
frametime = @elapsed begin
    push!(data, append!(to_value(data), rand(10)))
    #AbstractPlotting.update_limits!(scene) #comment out update calls for fixed axis
    #AbstractPlotting.update!(scene)
    end
    sleep(max(0.020-frametime, 0))
    println(frametime)
end

```

---

<div class="post-metadata">

### Author: ![JanKap](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jankap/32/22763_2.png) [@JanKap](https://discourse.julialang.org/u/JanKap)
#### Post date: [January 8, 2022, 10:21am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/13 "2022-01-08T10:21:32Z")

</div>

Since it’s been some time I’d like to ask if there’s any new development or best practices how to do (very) fast axis limits updates. My application is also a real time plot of sensor values with moving time axes.

However, the length of data shown could be static, e.g. 30 seconds. But it has to move like a sliding window. Does that help to increase performance?

Thanks a lot 🙂

---

<div class="post-metadata">

### Author: ![JamesNZ](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jamesnz/32/35361_2.png) [@JamesNZ](https://discourse.julialang.org/u/JamesNZ)
#### Post date: [June 30, 2024, 12:36am UTC](https://discourse.julialang.org/t/real-time-plotting-with-makie/20432/14 "2024-06-30T00:36:11Z")

</div>

I was curious about this too so here’s an updated version of @wsphillips’s script that let’s you pick between using `autolimits!()`, explicitly setting fixed limits, or not updating them at all:

```julia
using Printf
using Statistics
using GLMakie

function benchmark_plot(update_method)
    f = Figure()
    ax = Axis(f[1, 1]; title="Random data")
    data = Observable([Point2f(i, rand()) for i in 1:1000])
    lines!(ax, data)

    display(f)

    times::Vector{Float64} = Float64[]

    @time for i in 1:500
        new_points = [Point2f(length(data[]) + i, rand()) for i in 1:10]
        frametime = @elapsed begin
            data[] = append!(data[], new_points)

            if update_method == :explicit
                xlims!(ax, length(data[]) - 1000, length(data[]))
            elseif update_method == :auto
                autolimits!(ax)
            end
        end

        push!(times, frametime)
        sleep(max(0.020-frametime, 0))
    end

    @printf("Frame update time: %.5fs ± %.5f", mean(times), std(times))
end

```

And results on my machine, plotting fullscreen on a 2K monitor with integrated graphics:

```julia-repl
julia> benchmark_plot(:auto)
 11.174539 seconds (1.03 M allocations: 155.969 MiB, 1.08% gc time)
Frame update time: 0.01011s ± 0.00760
julia> benchmark_plot(:explicit)
 11.040334 seconds (1.37 M allocations: 185.142 MiB, 0.97% gc time)
Frame update time: 0.00763s ± 0.00561
julia> benchmark_plot(:none)
 11.080176 seconds (246.17 k allocations: 108.857 MiB, 0.48% gc time)
Frame update time: 0.00407s ± 0.00494

```

The numbers vary significantly depending on how big the plot is, but TL;DR `autolimits!()` is in the ballpark of ~2.5x slower on my system. Though that’s still ~10ms so not terrible I’d say.
