Playing with live plots in Pluto

I’m playing with live plotting using Pluto.jl. I have a simple plot updating at about 20 fps depending on what my computer is doing. I’m curious if anyone else is trying this sort of thing and if there are ways to get better performance (although this is pretty good for a live plot in my web browser!)

Here’s the small example I’m running:

### A Pluto.jl notebook ###
# v0.11.1

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
        el
    end
end

# ╔═╡ 66fb87f2-d356-11ea-2f32-9369eb3e12c7
begin
	using PlutoUI, Plots, DataStructures
	gr()
end;

# ╔═╡ 8ad7ccd0-d359-11ea-1b9b-cbd441322c19
begin
	ticks_per_sec =20
	ΔT = 1/ticks_per_sec
	last_time = [0.0]
	buffsize=500
	cb = CircularBuffer{Float64}(buffsize)
	cbt = CircularBuffer{Float64}(buffsize)
	fill!(cb,0.0)
	fill!(cbt,0.0)
end;

# ╔═╡ 6f7e7c70-d356-11ea-1570-61e70b58a488
@bind ticks Clock(ΔT,true)

# ╔═╡ b0e502d0-d359-11ea-0fd7-a74a05706fdb
begin
	ticks
	plot(cb,label="randwalk",leg=:left)
	plot!(cbt,label="framerate")
end

# ╔═╡ f4134320-d357-11ea-2871-05a13a891da2
begin
	ticks
	new_val = cb[end]+randn()
	push!(cb, new_val)
	new_time=time()
	delta = new_time-last_time[1]
	last_time[1]=new_time
	push!(cbt,1/delta)
end;

# ╔═╡ Cell order:
# ╟─b0e502d0-d359-11ea-0fd7-a74a05706fdb
# ╠═6f7e7c70-d356-11ea-1570-61e70b58a488
# ╠═66fb87f2-d356-11ea-2f32-9369eb3e12c7
# ╠═8ad7ccd0-d359-11ea-1b9b-cbd441322c19
# ╠═f4134320-d357-11ea-2871-05a13a891da2

P.S. If you’re not familiar with Pluto, it’s an reactive notebook tool. You run this example by using Pluto, Pluto.run() (which starts a web server) and then point your browser to localhost:1234 and open this file there.

1 Like

Hi!

Beyond 15 fps, the bottleneck is Julia code precompiling, because every time the ticks value updates, all code that depends on it needs to run again, going from string all the way to result.

You need to rewrite your notebooks into functions, and that’s really unfortunate! So only do it if you want to go above 15fps.

In your case, your first and last cell both depend on ticks. Rewrite it into a single function:

function compute_and_plot()
	new_val = cb[end]+randn()
	push!(cb, new_val)
	new_time=time()
	delta = new_time-last_time[1]
	last_time[1]=new_time
	push!(cbt,1/delta)

	plot(cb,label="randwalk",leg=:left)
	plot!(cbt,label="framerate")
end

and then you can have a single cell that depends on ticks (with a minimal amount of code to recompile):

let
	ticks
	compute_and_plot()
end

In the future, Pluto might do this automatically for you. That would make sliders superduper fast. It’s not easy to implement, (but Nathan Daly has given me a lot of good tips!) so it will take while.

6 Likes

Hey!
Tangentially related: I saw the Pluto.jl JuliaCon demo taking a webcam picture whilst in the notebook!. That is awesome - Is there any similar funcitonality that could happen to record voice / videos?
It would be great for demoing signal processing and FFTs!

1 Like

Yes! Someone showed this in a tweet! I have some sense of how it was done, but maybe you should reach out to them and ask for the notebook:

3 Likes

The function wrapping I suggested in my comment is now done automatically (interally) by Pluto. You do not need to rewrite your code into functions.

https://github.com/fonsp/Pluto.jl/pull/720

9 Likes