Code Monkey home page Code Monkey logo

d3-weighted-voronoi's Introduction

d3-weighted-voronoi

This d3 plugin produces a weighted Voronoi diagram. It tessellates/partitions the plane given a set of weighted two-dimensional sites.

Because a picture is worth a thousand words:

defaultVoronoi <== default / weighted ==> weightedVoronoi

Available only for d3 v4, d3 v5 and d3 v6.

This plugin is at the root of:

Context

Compared to the default Voronoï diagram, it adds the capability to assign a particular weight to each site. The higher is the weight of a site, the more this site influences its environment, and the larger is its surrounding area.

Weighted Voronoï diagrams come in severall flavours (additive/multiplicative, powered/not-powered, 2D/3D and higher dimensions, ..., cf. Wikipedia). This plugin focuses on the 2D additive weighted power diagram, which provides a tessellation made of convex hole-free polygons/cells with straight borders, as the default Voronoï diagram does.

Nonetheless, weighted Voronoï diagrams may have weird properties compared to default Voronoï diagrams:

  • a site may be outside it's zone of influence (ie. computed polygon)
  • a site may have no zone of influence

These situations arise when some sites are overweighted by others. You can experiment it in Voronoï playground : interactive weighted Voronoï study.

Examples

Installing

If you use NPM, npm install d3-weighted-voronoi. Otherwise, load https://rawcdn.githack.com/Kcnarf/d3-weighted-voronoi/v1.1.3/build/d3-weighted-voronoi.js (or its d3-weighted-voronoi.min.js version) to make it available in AMD, CommonJS, or vanilla environments. In vanilla, a d3 global is exported:

<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="https://rawcdn.githack.com/Kcnarf/d3-weighted-voronoi/v1.1.3/build/d3-weighted-voronoi.js"></script>
<script>
  var weightedVoronoi = d3.weightedVoronoi();
</script>

If you're interested in the latest developments, you can use the master build, available throught:

<script src="https://raw.githack.com/Kcnarf/d3-weighted-voronoi/master/build/d3-weighted-voronoi.js"></script>

TL;DR;

In your javascript, in order to define the tessellation:

var weightedVoronoi = d3.weightedVoronoi()
  .x(function(d){ return xScale(d); }                     // set the x coordinate accessor
  .y(function(d){ return yScale(d); }                     // set the y coordinate accessor
  .weight(function(d){ return weightScale(d); }           // set the weight accessor
  .clip([[0,0], [0,height], [width, height], [width,0]])  // set the clipping polygon

var cells = weightedVoronoi(data);                        // compute the weighted Voronoi tessellation

Then, later in your javascript, in order to draw cells:

d3.selectAll('path')
  .data(cells)
  .enter()
  .append('path')
  .attr('d', function (d) {
    return cellLiner(d) + 'z';
  });

Reference

API

# d3.weightedVoronoi()

Creates a new weightedVoronoi with the default x-, y-, weight- accessors, and clip, extent, size configuration values.

# weightedVoronoi(data)

Computes the weighted Voronoi diagram for the specified data points.

Returns a sparse array of polygons clipped to the clip polygon, one for each cell (each unique input point) in the diagram. Each polygon is represented as an array of points [x, y] where x and y are the point coordinates, a site field that refers to its site (ie. with x, y and weight retrieved from the original data), and a site.originalObject field that refers to the corresponding element in data. Polygons are open: they do not contain a closing point that duplicates the first point; a triangle, for example, is an array of three points. Polygons are also counterclockwise (assuming the origin ⟨0,0⟩ is in the top-left corner).

Note that weighted Voronoï diagrams may have weird properties compared to default Voronoï diagrams:

  • a site may be outside it's zone of influence (ie. computed polygon)
  • a site may have no zone of influence

These situations arise when some sites are overweighted by others. You can experiment it in Voronoï playground : interactive weighted Voronoï study.

# weightedVoronoi.x([x])

If x is specified, sets the x-coordinate accessor. If x is not specified, returns the current x-coordinate accessor, which defaults to:

function x(d) {
  return d.x;
}

# weightedVoronoi.y([y])

If y is specified, sets the y-coordinate accessor. If y is not specified, returns the current y-coordinate accessor, which defaults to:

function y(d) {
  return d.y;
}

# weightedVoronoi.weight([weight])

If weight is specified, sets the weight accessor. If weight is not specified, returns the current weight accessor, which defaults to:

function weight(d) {
  return d.weight;
}

# weightedVoronoi.clip([clip])

If clip is specified, sets the clipping polygon, compute the adequate extent and size, and returns this layout. clip must define a hole-free concave polygon, and must be specified as an array of 2D points [x, y], which must be (i) open (no duplication of the first D2 point) and (ii) counterclockwise (assuming the origin ⟨0,0⟩ is in the top-left corner). If clip is not specified, returns the current clipping polygon, which defaults to:

[
  [0, 0],
  [0, 1],
  [1, 1],
  [1, 0],
];

# weightedVoronoi.extent([extent])

If extent is specified, it is a convenient way to define the clipping polygon as a rectangle. It sets the extent, computes the adequate clipping polygon and size, and returns this layout. extent must be a two-element array of 2D points [x, y], which defines the clipping polygon as a rectangle with the top-left and bottom-right corners respectively set to the first and second points (assuming the origin ⟨0,0⟩ is in the top-left corner on the screen). If extent is not specified, returns the current extent, which is [[minX, minY], [maxX, maxY]] of current clipping polygon, and which defaults to:

[
  [0, 0],
  [1, 1],
];

# weightedVoronoi.size([size])

If size is specified, it is a convenient way to define the clipping polygon as a rectangle. It sets the size, computes the adequate clipping polygon and extent, and returns this layout. size must be a two-element array of numbers [width, height], which defines the clipping polygon as a rectangle with the top-left corner set to [0, 0]and the bottom-right corner set to [width, height](assuming the origin ⟨0,0⟩ is in the top-left corner on the screen). If size is not specified, returns the current size, which is [maxX-minX, maxY-minY] of current clipping polygon, and which defaults to:

[1, 1];

Dependencies

  • d3-array.extent
  • d3-polygon.{polygonHull, polygonLenght}

Semantic Versioning

d3-weighted-voronoi attempts to follow semantic versioning and bump major version only when backwards incompatible changes are released.

d3-weighted-voronoi's People

Contributors

dependabot[bot] avatar kcnarf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

d3-weighted-voronoi's Issues

I get an infinite loop in ConvexHull.prototype.compute

next.conflicts.isEmpty() is false, so current is not increased
this.visible[jF].getHorizon() is null
this.horizon.length is 0
first and last are null
this.created.length is 0, so current is not increased

repeat...

Input to _weightedVoronoi :

[[0.3,-1.5,1.7542563288623765],[-0.3,-1.5,1.7542563288623765],[0.3,-0.8999999999999999,1.7542563288623765],[-0.3,-0.8999999999999999,1.7542563288623765],[-0.3,-0.3,1.7542563288623765],[-0.8999999999999999,-0.8999999999999999,1.7542563288623765],[0.8999999999999999,-1.5,1.7542563288623765],[-0.8999999999999999,-1.5,1.7542563288623765]]

"Cannot read property 'x' of null" with identical sites (same locations, same weights)

2 sites with the same x, y and weight raise a "Cannot read property 'x' of null".

stackTrace:
Uncaught TypeError: Cannot read property 'x' of null
at dot (VM2965 d3-weighted-voronoi.js:16)
at Face.orient (VM2965 d3-weighted-voronoi.js:399)
at ConvexHull.prep (VM2965 d3-weighted-voronoi.js:531)
at ConvexHull.compute (VM2965 d3-weighted-voronoi.js:635)
at computePowerDiagramIntegrated (VM2965 d3-weighted-voronoi.js:792)
at _weightedVoronoi (VM2965 d3-weighted-voronoi.js:876)
at computeAllCells (blob:http://blockbuilder.org/7558f499-9ca0-4287-9051-82ab1eb0ca1e:345)
at blob:http://blockbuilder.org/7558f499-9ca0-4287-9051-82ab1eb0ca1e:335

data:
[{x:halfWidth, y:halfHeight, weight: 0},
{x:halfWidth, y:halfHeight, weight: 0}]

why is index == 0 for all cells?

Two questions about the cell<->site correspondance

  1. How can I easily get all points that have no matching cell? In the classic (non-weighted) voronoi, all cells are returned in the same order as the points, but here it seems different.

  2. In https://observablehq.com/d/128a52368e482305 I can see that for all cells we have cell.site.index == 0. Is this expected?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.