# Voronoi Visualization

**URL:** <https://discourse.julialang.org/t/voronoi-visualization/36602>\
**Category:** Visualization\
**Created:** [March 27, 2020, 2:53pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602 "2020-03-27T14:53:21Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![gideonsimpson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gideonsimpson/32/1928_2.png) [@gideonsimpson](https://discourse.julialang.org/u/gideonsimpson)\
**Post date:** [March 27, 2020, 2:53pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/1 "2020-03-27T14:53:21Z")

</div>

I have a set of points in 2D that I’m using to define Voronoi cells using `NearestNeighbors.jl`. I’d like to do some visualization of this. The two things I would ideally like to be able to do:

1. Plot the Voronoi cells
2. Color/shade the Voronoi cells according to a specified function of the Voronoi cell centers

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 27, 2020, 3:12pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/2 "2020-03-27T15:12:32Z")

</div>

That should be fairly simple but I don’t think voronoidelaunay has recipes. Could you post an mwe, I guess it wouldn’t be hard to write a recipe (if noone has solved it before I’ll check back here on Tuesday).

But - basically your Vector shoult extract each cell as a Vector of vertices, use the `@series` macro to create a new series for each cell (with `label = ""`), and in that block return a vector of xs and a vector of ys, setting `seriestype := :shape`. You can then use the `fill_z` keyword to color the cells by a number or function.

---

<div class="post-metadata">

**Author:** ![gideonsimpson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gideonsimpson/32/1928_2.png) [@gideonsimpson](https://discourse.julialang.org/u/gideonsimpson)\
**Post date:** [March 27, 2020, 4:16pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/3 "2020-03-27T16:16:12Z")

</div>

The issue is, partly, that I start with the Voronoi cell centers. I don’t know how to turn them into the cell vertices/edges.

---

<div class="post-metadata">

**Author:** ![joa-quim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joa-quim/32/227_2.png) [@joa-quim](https://discourse.julialang.org/u/joa-quim)\
**Post date:** [March 27, 2020, 4:28pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/4 "2020-03-27T16:28:52Z")

</div>

We have added that recently to GMT (the C lib), but it’s only available in its dev version (next version, GMT6.1.0, will come out in one or two weeks). With it, one can do

```julia
using GMT
G = nearneighbor("lixo.csv", region=(0,10,0,10), N="n", I=0.05);
imshow(G, fmt=:png)

```

where `lixo.csv` is a demo file with

```julia
2.53857 5.16657 0
2.48365 6.26811 1
8.68883 4.55983 2
4.11104 7.78623 3
1.79704 6.53027 4
7.17493 3.81713 5
3.41052 8.18161 6
8.35062 1.43348 7
8.17060 4.46765 8
5.27815 1.15172 9

```

and get

 ![GMTjl_tmp](https://global.discourse-cdn.com/julialang/original/3X/2/5/259d15e85309331cf31c232de96ed247f1ebac5e.png)

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 31, 2020, 9:33pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/5 "2020-03-31T21:33:50Z")

</div>

I tried extracting the Voronoi edges from VoronoiDelaunay. What. A. Rabbit. Hole. I might get back to you on that, but otherwise the “raster” approach shown by joa-quim is of course very easy. With Plots and NearestNeighbors it would look something like this:

```julia
using Plots, NearestNeighbors

# some function of the center point to color by - here the product of the coordinates
function col(i, j, kdtree, data)
    id, dist = knn(kdtree, [i,j], 1)
    nearest = data[:,id]
    nearest[1]*nearest[2]
end

# build the neighbor tree
data = rand(2, 100)
kdtree = KDTree(data)

# color every point by its nearest center
heatmap([col(i, j, kdtree, data) for i in 0:0.001:1, j in 0:0.001:1], c = :viridis)

```

 ![Screenshot 2020-03-31 at 23.33.18](https://global.discourse-cdn.com/julialang/original/3X/0/1/0184d8928947942a278e06085bc0659e46636a02.png)

---

<div class="post-metadata">

**Author:** ![anon92994695](https://avatars.discourse-cdn.com/v4/letter/a/ce7236/32.png) [@anon92994695](https://discourse.julialang.org/u/anon92994695)\
**Post date:** [March 31, 2020, 9:45pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/6 "2020-03-31T21:45:54Z")

</div>

Voronoi tesselations, and their duals are almost always a huge hardship to contend with. I have yet to see a “clean” implementation, but, that being said, I would LOVE to have first class spatial partitioning and visualizations of such in Julia.

I’m personally a big fan of the line drawings, with the barycenters of the voronoi cells represented with dots.

The really tricky bit is doing this in 3-Space… 😅 I tried once… Maybe someone from #geometry wou;d be able too, I’m too mortal.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 31, 2020, 10:11pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/7 "2020-03-31T22:11:47Z")

</div>

Line drawings are easy though. It’s the polygons that are hard to extract.

```julia
x, y = rand(100).+1, rand(100).+1 #yeah the package only accepts input data in the (1,2) range
tess = DelaunayTessellation()
push!(tess, Point2D.(x,y))
scatter(x,y, lims = (1,2), legend = false)
plot!(getplotxy(voronoiedges(tess))...)

```

 ![Screenshot 2020-04-01 at 00.11.18](https://global.discourse-cdn.com/julialang/original/3X/8/2/82a4e1894187d8eadec5187a8d3066ba9c3b693b.png)

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [March 31, 2020, 10:36pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/8 "2020-03-31T22:36:09Z")

</div>

This clumsy long code gives me most of the polygons - but the input order is lost, so it’s difficult to color the polygons by the center points. I think the raster approach is likely the best.

```julia
using VoronoiDelaunay, Plots

# create a polygon by putting all the edges (point pairs) in order (the order is seemingly random in the package)
function getpoly(eds)
    a = geta.(eds)
    b = getb.(eds)
    ret = Point2D[a[1], b[1]]
    ind = 1
    for i in 1:length(a)
        inds = setdiff(findall(x->x ≈ ret[end], a), [ind])
        if !isempty(inds)
            ind = inds[1]
            push!(ret, b[ind])
        else
            inds = setdiff(findall(x->x ≈ ret[end], b), [ind])
            ind = inds[1]
            push!(ret, a[ind])
        end
    end
    push!(ret, a[1])
    ret
end

Base.isapprox(pt1::Point2D, pt2::Point2D) = pt1._x ≈ pt2._x && pt1._y ≈ pt2._y

# create polygons by filtering all of the edges for each point
function getpolys(tess::DelaunayTessellation2D{Point2D})
    edges = collect(voronoiedges(tess))
    ret = Vector{Point2D}[]
    for pt in unique([getgenb.(edges); getgena.(edges)])
        ed = filter(x-> getgena(x) ≈ pt || getgenb(x) ≈ pt, edges)
        try
            push!(ret, getpoly(ed))
        catch
        end
    end
    ret
end

@recipe f(pts::AbstractVector{<:Point2D}) = getx.(pts), gety.(pts)

@recipe function f(D::DelaunayTessellation2D{Point2D})
    label := ""
    for poly in getpolys(D)
        @series begin
            seriestype := :shape
            poly
        end
    end
    ()
end

# some random data
x, y = rand(100).+1, rand(100).+1
tess = DelaunayTessellation()
push!(tess, Point2D.(x,y))
plot(tess, lims = (1,2), lc = :white)

```

 ![Screenshot 2020-04-01 at 00.35.53](https://global.discourse-cdn.com/julialang/original/3X/c/e/cec7379ccf46204c346a254dbb1ba4c4aecda1b0.png)

---

<div class="post-metadata">

**Author:** ![joa-quim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joa-quim/32/227_2.png) [@joa-quim](https://discourse.julialang.org/u/joa-quim)\
**Post date:** [April 1, 2020, 12:16am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/9 "2020-04-01T00:16:49Z")

</div>

@mkborregaard you can get the Voronoi polygons with the GMT’s `triangulate` program

```julia
D = triangulate("lixo.csv", region=(0,10,0,10), voronoi="n", network=true);
triangulate [WARNING]: -Qn is experimental and unstable.

plot(D, aspect="equal")
plot!("lixo.csv", marker=:circle, ms=0.2, fill=:black, fmt=:png, show=true)

```

 ![GMTjl_tmp](https://global.discourse-cdn.com/julialang/original/3X/d/9/d9aec5822b1948d4bcf28933c2385f2dd1dc6c00.png)

---

<div class="post-metadata">

**Author:** ![anon92994695](https://avatars.discourse-cdn.com/v4/letter/a/ce7236/32.png) [@anon92994695](https://discourse.julialang.org/u/anon92994695)\
**Post date:** [April 1, 2020, 1:11am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/10 "2020-04-01T01:11:31Z")

</div>

can you get the barycenters of the cells with GMT?

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [April 1, 2020, 4:58am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/11 "2020-04-01T04:58:12Z")

</div>

Sweet! But are those polygons or outlines? Can you colour in the polygon area?

---

<div class="post-metadata">

**Author:** ![joa-quim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joa-quim/32/227_2.png) [@joa-quim](https://discourse.julialang.org/u/joa-quim)\
**Post date:** [April 1, 2020, 10:15am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/12 "2020-04-01T10:15:32Z")

</div>

The GMT [man page](https://docs.generic-mapping-tools.org/dev/gmtspatial.html#q) for the `gmtspatial` module says

``… The centroid is computed using the mean of the 3-D Cartesian vectors making up the polygon vertices, while the area is obtained via an equal-area projection. ```

Is this what you want?

```julia
julia> D = triangulate("lixo.csv", region=(0,10,0,10), voronoi="n", network=true);
triangulate [WARNING]: -Qn is experimental and unstable.

julia> Dc = gmtspatial(D, Q=true) # Compute centroid and area of each polygon
Array{GMT.GMTdataset,1} with 1 segments
First segment DATA
10×3 Array{Float64,2}:
 3.01992 6.50059 2.43609
 2.67102 4.2825 16.4437
 5.8361 7.53071 15.0461
 1.10002 6.92018 7.91042
 2.13613 8.88082 7.76614
 6.23657 4.08067 8.62185
 3.65584 1.24974 15.8507
 8.46981 1.81582 8.66603
 7.80101 5.09087 5.20239
 9.11705 6.79032 12.0565

julia> plot(D, aspect="equal")![GMTjl_tmp|504x500]
julia> plot!(Dc, marker=:circle, ms=0.2, fill=:black, fmt=:png, show=true)

```

 ![GMTjl_tmp](https://global.discourse-cdn.com/julialang/original/3X/6/3/633c2fce0d826866c8521c1362051fe1c2bdefa7.png)

---

<div class="post-metadata">

**Author:** ![joa-quim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joa-quim/32/227_2.png) [@joa-quim](https://discourse.julialang.org/u/joa-quim)\
**Post date:** [April 1, 2020, 10:17am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/13 "2020-04-01T10:17:48Z")

</div>

Yes, they are polygons and yes they can be painted. I’ll prepare an example.

---

<div class="post-metadata">

**Author:** ![joa-quim](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joa-quim/32/227_2.png) [@joa-quim](https://discourse.julialang.org/u/joa-quim)\
**Post date:** [April 1, 2020, 11:03am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/14 "2020-04-01T11:03:41Z")

</div>

OK, painting the polygons uncovered an issue in the GMT.jl wrapper and a feature in the GMT program `triangulate` itself. So I have to resort to the hard core GMT syntax to show it. The issue is how to color the polygons with a colormap. Next version of GMT has a more handy way of assigning colors to polygons. But for now, this works and will be made nicer to read when I fix the wrapper issue.

```julia
D,G = triangulate("lixo.csv", region=(0,10,0,10), voronoi="n", grid=true, inc=0.05, network=true, edges=true);
triangulate [WARNING]: -Qn is experimental and unstable.

C = makecpt(cmap=:categorical, range=(0,10,1), cptname="categorical.cpt");
plot("-JX12c/0 -Baf -BWSen -Ccategorical.cpt -R-0.4/10.4/-0.4/10.4 -W1p+cf -P > voro_color.ps", D)

```

 ![voro_color](https://global.discourse-cdn.com/julialang/original/3X/4/2/429819c2e3a7589462c46f44cee69bd941d30e07.png)

OK, for the record. The [GMT.jl](https://github.com/GenericMappingTools/GMT.jl) issue was just an harmless wrong warning and the GMT feature was actually my lack of attention reading the manual. The image above (and with the file posted at the beginning of this thread) can be obtained with

```julia
using GMT
D = triangulate("lixo.csv", region=(0,10,0,10), voronoi="n", network=true, xyz=true);
triangulate [WARNING]: -Qn is experimental and unstable.

C = makecpt(cmap=:categorical, range=(0,10,1));
plot(D, color=C, aspect=:equal, show=true, pen=(lw=1, csymbol=true), savefig="voronoi_colored.png")

```

---

<div class="post-metadata">

**Author:** ![anon92994695](https://avatars.discourse-cdn.com/v4/letter/a/ce7236/32.png) [@anon92994695](https://discourse.julialang.org/u/anon92994695)\
**Post date:** [April 1, 2020, 7:40pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/15 "2020-04-01T19:40:59Z")

</div>

yes that is what I wanted :). I’ll have to look at this package thank you!

---

<div class="post-metadata">

**Author:** ![gideonsimpson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gideonsimpson/32/1928_2.png) [@gideonsimpson](https://discourse.julialang.org/u/gideonsimpson)\
**Post date:** [April 1, 2020, 11:31pm UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/16 "2020-04-01T23:31:25Z")

</div>

This, and the one below, [Voronoi Visualization - #14 by joa-quim](https://discourse.julialang.org/t/voronoi-visualization/36602/14), are exactly what I would like to be able to do.

---

<div class="post-metadata">

**Author:** ![mkborregaard](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkborregaard/32/556_2.png) [@mkborregaard](https://discourse.julialang.org/u/mkborregaard)\
**Post date:** [April 2, 2020, 7:42am UTC](https://discourse.julialang.org/t/voronoi-visualization/36602/17 "2020-04-02T07:42:47Z")

</div>

It does look a lot easier with GMT in this case. The issue is not in Plots, but lies in the VoronoiDelaunay package being particularly optimised for edges but ignorant of polygons. So all my code does is that it tries to group and sort all the disparate unsorted edges to form valid polygons. Once you have them plotting is easy. I’ll be honest and say I find the VoronoiDelaunay package interface very little focused on user experience and very much on internal performance. I’m considering doing a wrapper package with the opposite trade-off…

If you are keen to use Plots, a userplot recipe extracting the centers from the tess object again could do the trick. Happy to give it a go, but let me know if you’ll just use the GMT instead, which seems to be simple and work.
