Skip to content

Instantly share code, notes, and snippets.

@theogf
Last active March 16, 2021 09:03
Show Gist options
  • Save theogf/22bcc3f7ebee0939556aff795822a1ec to your computer and use it in GitHub Desktop.
Save theogf/22bcc3f7ebee0939556aff795822a1ec to your computer and use it in GitHub Desktop.
Sample code for generating a Mondrian process and plotting it
using CairoMakie
# using Animations
using Distributions
using Random
using AbstractTrees
CairoMakie.activate!()
mutable struct Partition
x
y
t
p1
p2
end
AbstractTrees.children(p::Partition) = p.p1 != [] ? (p.p1, p.p2) : ()
AbstractTrees.printnode(io::IO, p::Partition) = print(io, "x=$(p.x), y=$(p.y), t=$(p.t)")
## Create a Breadth-First iterator
struct BFS
p::Partition
end
Base.iterate(d::BFS) = (d.p, children(p))
Base.iterate(::BFS, state) = (first(state), (Base.tail(state)..., children(first(state))...))
Base.iterate(::BFS, ::Tuple{}) = nothing
## Create the partitioning process
function dring(p::Partition)
λs = [diff(p.x)[1], diff(p.y)[1]]
t_drings = rand.(Exponential.(inv.(λs)))
t, d = findmin(t_drings)
if p.t + t > t_end
return p
else
if d==1
p.p1, p.p2 = cutx(p, t)
else
p.p1, p.p2 = cuty(p, t)
end
return p
end
end
## Cut on the x axis
function cutx(p::Partition, t)
cut = rand(Uniform(p.x...))
return dring(Partition([p.x[1], cut], p.y, p.t + t, [], [])), dring(Partition([cut, p.x[2]], p.y, p.t + t, [], []))
end
## Cut on the y axis
function cuty(p::Partition, t)
cut = rand(Uniform(p.y...))
return dring(Partition(p.x, [p.y[1], cut], p.t + t, [], [])), dring(Partition(p.x, [cut, p.y[2]], p.t + t, [], []))
end
## Plotting helpers
function corners(p::Partition)
Point2f0.([[p.x[1], p.y[1]], [p.x[2], p.y[1]], [p.x[2], p.y[2]], [p.x[1], p.y[2]], [p.x[1], p.y[1]]])
end
## Run algorithm
λ = 2.0
t_end = rand(Exponential(λ))
p0 = Partition([0.0, 1.0], [0.0, 1.0], 0, [], [])
p = dring(p0)
print_tree(p)
## Plotting all the leaves
AbstractPlotting.inline!(true)
fig = Figure()
ax = fig[1,1] = Axis(fig, title="Mondrian Process")
hidedecorations!(ax)
for p in Leaves(p)
poly!(ax,
corners(p),
color=rand([:blue, :red, :white, :black, :yellow]),
strokecolor=:black,
strokewidth=4,
)
end
display(fig)
## Plotting the partitioning process
fig = Figure()
ax = fig[1,1] = Axis(fig, title="Mondrian Process")
hidedecorations!(ax)
record(fig, "mondrian.gif", fps=5) do io
for p in BFS(p)
poly!(ax,
corners(p),
color=rand([:blue, :red, :white, :black, :yellow]),
strokecolor=:black,
strokewidth=4,
)
fig |> display
recordframe!(io)
end
end
## Trying to plot with UnicodePlots
## Plotting with UnicodePlots
import UnicodePlots
function UnicodePlots.lineplot!(canvas::UnicodePlots.Plot, p::Partition, args...; kwargs...)
for p in Leaves(p)
UnicodePlots.lineplot!(canvas, first.(corners(p)), last.(corners(p)), args...; kwargs...)
end
end
function UnicodePlots.lineplot(p::Partition, args...; kwargs...)
plt = UnicodePlots.Plot(UnicodePlots.BrailleCanvas(40, 10, # number of columns and rows (characters)
origin_x = 0., origin_y = 0., # position in virtual space
width = 1., height = 1.)) # size of the virtual space
UnicodePlots.lineplot!(plt, p)
return plt
end
UnicodePlots.lineplot(p0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment