{"id":13426274,"url":"https://github.com/Kcnarf/d3-voronoi-treemap","last_synced_at":"2025-03-15T21:30:52.230Z","repository":{"id":27547461,"uuid":"112339660","full_name":"Kcnarf/d3-voronoi-treemap","owner":"Kcnarf","description":"D3 plugin which computes a treemap based on a Voronoi tesselation","archived":false,"fork":false,"pushed_at":"2024-09-26T21:18:33.000Z","size":801,"stargazers_count":204,"open_issues_count":2,"forks_count":19,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-10-11T11:15:37.744Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Kcnarf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-28T13:35:04.000Z","updated_at":"2024-09-28T22:55:07.000Z","dependencies_parsed_at":"2024-10-25T10:14:42.770Z","dependency_job_id":"310f7ce9-da2c-47b4-944d-dec105e6e296","html_url":"https://github.com/Kcnarf/d3-voronoi-treemap","commit_stats":{"total_commits":84,"total_committers":5,"mean_commits":16.8,"dds":0.3928571428571429,"last_synced_commit":"f641feeea2fee9ae384d964d08088e4b963df1f2"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kcnarf%2Fd3-voronoi-treemap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kcnarf%2Fd3-voronoi-treemap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kcnarf%2Fd3-voronoi-treemap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Kcnarf%2Fd3-voronoi-treemap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Kcnarf","download_url":"https://codeload.github.com/Kcnarf/d3-voronoi-treemap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243792310,"owners_count":20348615,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T00:01:30.660Z","updated_at":"2025-03-15T21:30:51.895Z","avatar_url":"https://github.com/Kcnarf.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Utils"],"sub_categories":[],"readme":"# d3-voronoi-treemap\n\nThis D3 plugin produces a _Voronoï treemap_. Given a convex polygon and nested weighted data, it tesselates/partitions the polygon in several inner cells which represent the hierarchical structure of your data, such that the area of a cell represents the weight of the underlying datum.\n\nBecause a picture is worth a thousand words:\n\n![square](./img/square.png)\n![hexagon](./img/hexagon.png)\n![diamond](./img/diamond.png)\n![circle](./img/circle.png)\n\nAvailable only for **d3 v4**, **d3 v5** and **d3 v6**.\n\nIf you're interested on one-level map, take a look at the [d3-voronoi-map](https://github.com/Kcnarf/d3-voronoi-map) plugin, which may be simpler to use (no need of a d3-hierarchy).\n\n## Context\n\nD3 already provides a [d3-treemap](https://github.com/d3/d3-hierarchy/blob/master/README.md#treemap) module which produces a rectangular treemap. Such treemaps could be distorted to fit shapes that are not rectangles (cf. [Distorded Treemap - d3-shaped treemap](http://bl.ocks.org/Kcnarf/976b2e854965eea17a7754517043b91f)).\n\nThis plugin allows to compute a treemap with a unique look-and-feel, where inner areas are not strictly aligned each others, and where the outer shape can be any hole-free convex polygons (squares, rectangles, pentagon, hexagon, ... any regular convex polygon, and also any non regular hole-free convex polygon).\n\nThe drawback is that the computation of a Voronoï treemap is based on a iteration/looping process. Hence, it requires _some times_, depending on the number and type of data/weights, the desired representativeness of cell areas.\n\n## Examples\n\n- Real life use cases\n  - [https://unearthed.greenpeace.org/2020/02/20/pesticides-croplife-hazardous-bayer-syngenta-health-bees/] by Nadieh Bremer for Greenpeace (more details at https://www.visualcinnamon.com/portfolio/highly-hazardous-pesticides)\n  - [Brussels. A lovely Melting-Pot.](http://brussels-diversity.jetpack.ai/) by Karim Douieb, with a really great animation that clearly and easily explains to the reader how to read/understand the Voronoï treemap\n  - [Earth's Land Surface](https://public.tableau.com/profile/luca7027#!/vizhome/EarthsLandSurfaceAVoronoiWorld/EarthsLandSurfaceAVoronoiWorld) by Luca Urzì in Tableau\n- Examples with available code\n  - [The Global Economy by GDP](https://bl.ocks.org/Kcnarf/fa95aa7b076f537c00aed614c29bb568), a remake of [HowMuch.net's article](https://howmuch.net/articles/the-global-economy-by-GDP)\n\n## Installing\n\nIf you use NPM, `npm install d3-voronoi-treemap`. Otherwise, load `https://rawcdn.githack.com/Kcnarf/d3-voronoi-treemap/v1.1.2/build/d3-voronoi-treemap.js` (or its `d3-voronoi-treemap.min.js` version) to make it available in AMD, CommonJS, or vanilla environments. In vanilla, you must load the [d3-weighted-voronoi](https://github.com/Kcnarf/d3-weighted-voronoi) and [d3-voronoi-map](https://github.com/Kcnarf/d3-voronoi-map) plugins prioir to this one, and a d3 global is exported:\n\n```html\n\u003cscript src=\"https://d3js.org/d3.v6.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://rawcdn.githack.com/Kcnarf/d3-weighted-voronoi/v1.1.3/build/d3-weighted-voronoi.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://rawcdn.githack.com/Kcnarf/d3-voronoi-map/v2.1.1/build/d3-voronoi-map.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://rawcdn.githack.com/Kcnarf/d3-voronoi-treemap/v1.1.2/build/d3-voronoi-treemap.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  var voronoiTreemap = d3.voronoiTreemap();\n\u003c/script\u003e\n```\n\nIf you're interested in the latest developments, you can use the master build, available throught:\n\n```html\n\u003cscript src=\"https://raw.githack.com/Kcnarf/d3-voronoi-treemap/master/build/d3-voronoi-treemap.js\"\u003e\u003c/script\u003e\n```\n\n## TL;DR;\n\nIn your javascript, in order to define the tessellation:\n\n```javascript\nfunction weightAccessor(d) {\n  return d.weight; // computes the weight of one of your data; depending on your data, it may be 'd.area', or 'd.percentage', ...\n}\nvar rootNode = d3.hierarchy(nestedData); // a d3-hierarchy of your nested data\nrootNode.sum(weightAccessor); // assigns the adequate weight to each node of the d3-hierarchy\n\nvar voronoiTreemap = d3.voronoiTreemap().clip([\n  [0, 0],\n  [0, height],\n  [width, height],\n  [width, 0],\n]); // sets the clipping polygon\nvoronoiTreemap(rootNode); // computes the weighted Voronoi tessellation of the d3-hierarchy; assigns a 'polygon' property to each node of the hierarchy\n```\n\nThen, later in your javascript, in order to draw cells:\n\n```javascript\nvar allNodes = rootNode.descendants();\nd3.selectAll('path')\n  .data(allNodes)\n  .enter()\n  .append('path')\n  .attr('d', function (d) {\n    // d is a node\n    return d3.line()(d.polygon) + 'z'; // d.polygon is the computed Voronoï cell encoding the relative weight of your underlying original data\n  })\n  .style('fill', function (d) {\n    return fillScale(d.data); // d.data is your original data\n  });\n```\n\n## Reference\n\n- based on [Computing Voronoï Treemaps - Faster, Simpler, and Resolution-independent ](https://www.uni-konstanz.de/mmsp/pubsys/publishedFiles/NoBr12a.pdf)\n- [https://github.com/ArlindNocaj/power-voronoi-diagram](https://github.com/ArlindNocaj/power-voronoi-diagram) for a Java implementation\n\n## API\n\n\u003ca name=\"voronoiTreemap\" href=\"#voronoiTreemap\"\u003e#\u003c/a\u003e d3.\u003cb\u003evoronoiTreemap\u003c/b\u003e()\n\nCreates a new voronoiTreemap with the default configuration values and functions ([_clip_](#voronoiTreemap_clip), [_extent_](#voronoiTreemap_extent), [_size_](#voronoiTreemap_size), [_convergenceRatio_](#voronoiTreemap_convergenceRatio), [_maxIterationCount_](#voronoiTreemap_maxIterationCount), [_minWeightRatio_](#voronoiTreemap_minWeightRatio) and [_prng_](#voronoiTreemap_prng)).\n\n\u003ca name=\"_voronoiTreemap\" href=\"#_voronoiTreemap\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e(\u003ci\u003eroot\u003c/i\u003e)\n\nComputes the **Voronoï treemap** for the specified [d3-hierarchy](https://github.com/d3/d3-hierarchy#hierarchy), where _root_ is the root node of the hierarchy, assigning a _polygon_ property on the root and its descendants. A 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).\n\nAs others d3-hierarchy layouts (rectangular treemap, or circle packing), the Voronoï treemap layout considers the weight of a node to be the _value_ propertyof that node. Hence, you **must** call [root.sum](https://github.com/d3/d3-hierarchy#node_sum) before passing the hierarchy to the Voronoï treemap layout, in order to properly set the _value_ property of each node (root, intermediates and leaves). For example, considering that your original nested data have leaves with a _weight_ property, you must use `rootNode.sum(function(d){ return d.weight; })`.\n\n\u003ca name=\"voronoiTreemap_clip\" href=\"#voronoiTreemap_clip\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003eclip\u003c/b\u003e([\u003ci\u003eclip\u003c/i\u003e])\n\nIf _clip_ is specified, sets the clipping polygon, , compute the adequate [_extent_](#voronoiTreemap_extent) and [_size_](#voronoiTreemap_size), and returns this layout . _clip_ defines a hole-free convex polygon, and is 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:\n\n```js\n[\n  [0, 0],\n  [0, 1],\n  [1, 1],\n  [1, 0],\n];\n```\n\n\u003ca name=\"voronoiTreemap_extent\" href=\"#voronoiTreemap_extent\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003eextent\u003c/b\u003e([\u003ci\u003eextent\u003c/i\u003e])\n\nIf _extent_ is specified, it is a convenient way to define the clipping polygon as a rectangle. It sets the extent, computes the adequate [_clip_](#voronoiTreemap_clip)ping polygon and [_size_](#voronoiTreemap_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:\n\n```js\n[\n  [0, 0],\n  [1, 1],\n];\n```\n\n\u003ca name=\"voronoiTreemap_size\" href=\"#voronoiTreemap_size\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003esize\u003c/b\u003e([\u003ci\u003esize\u003c/i\u003e])\n\nIf _size_ is specified, it is a convenient way to define the clipping polygon as a rectangle. It sets the size, computes the adequate [_clip_](#voronoiTreemap_clip)ping polygon and [_extent_](#voronoiTreemap_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:\n\n```js\n[1, 1];\n```\n\n\u003ca name=\"voronoiTreemap_convergenceRatio\" href=\"#voronoiTreemap_convergenceRatio\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003econvergenceRatio\u003c/b\u003e([\u003ci\u003econvergenceRatio\u003c/i\u003e])\n\nIf _convergenceRatio_ is specified, sets the convergence ratio, which stops computation when (cell area errors / ([_clip_](#voronoiTreemap_clip)-ping polygon area) \u003c= _convergenceRatio_. If _convergenceRatio_ is not specified, returns the current _convergenceRatio_ , which defaults to:\n\n```js\nvar convergenceRatio = 0.01; // stops computation when cell area error \u003c= 1% clipping polygon's area\n```\n\nThe smaller the _convergenceRatio_, the more representative is the treemap, the longer the computation takes time.\n\n\u003ca name=\"voronoiTreemap_maxIterationCount\" href=\"#voronoiTreemap_maxIterationCount\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003emaxIterationCount\u003c/b\u003e([\u003ci\u003emaxIterationCount\u003c/i\u003e])\n\nIf _maxIterationCount_ is specified, sets the maximum allowed number of iterations, which stops computation when it is reached, even if the [_convergenceRatio_](#voronoiTreemap_convergenceRatio) is not reached. If _maxIterationCount_ is not specified, returns the current _maxIterationCount_ , which defaults to:\n\n```js\nvar maxIterationCount = 50;\n```\n\nIf you want to wait until computation stops _only_ when the [_convergenceRatio_](#voronoiTreemap_convergenceRatio) is reached, just set the _maxIterationCount_ to a large amount. Be warned that computation may take a huge amount of time, due to flickering behaviours in later iterations.\n\n\u003ca name=\"voronoiTreemap_minWeightRatio\" href=\"#voronoiTreemap_minWeightRatio\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003eminWeightRatio\u003c/b\u003e([\u003ci\u003eminWeightRatio\u003c/i\u003e])\n\nIf _minWeightRatio_ is specified, sets the minimum weight ratio, which allows to compute the minimum allowed weight (_= maxWeight \\* minWeightRatio_). If _minWeightRatio_ is not specified, returns the current _minWeightRatio_ , which defaults to:\n\n```js\nvar minWeightRatio = 0.01; // 1% of maxWeight\n```\n\n_minWeightRatio_ allows to mitigate flickerring behaviour (caused by too small weights), and enhances user interaction by not computing near-empty cells.\n\n\u003ca name=\"voronoiTreemap_prng\" href=\"#voronoiTreemap_prng\"\u003e#\u003c/a\u003e \u003ci\u003evoronoiTreemap\u003c/i\u003e.\u003cb\u003eprng\u003c/b\u003e([\u003ci\u003eprng\u003c/i\u003e])\n\nIf _prng_ is specified, sets the pseudorandom number generator which is used when randomness is required (i.e. when setting intial random position of data/seeds). The given pseudorandom number generator must implement the same interface as `Math.random` and must only return values in the range [0, 1). If _prng_ is not specified, returns the current _prng_ , which defaults to `Math.random`.\n\nConsidering the same set of data, severall Voronoï treemap computations lead to disctinct final arrangements, due to the non-seedable `Math.random` number generator. If _prng_ is set to a _seedable_ PRNG which produces repeatable results, then several computations will produce the exact same final arrangement. This is useful if you want the same arrangement for distinct page loads/reloads. For example, using [seedrandom](https://github.com/davidbau/seedrandom):\n\n```js\n\u003cscript src=\"//cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.3/seedrandom.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  var mySeededPrng = new Math.seedrandom('my seed'); // (from seedrandom's doc) Use \"new\" to create a local prng without altering Math.random\n  voronoiTreemap.prng(mySeededPrng);\n\u003c/script\u003e\n```\n\nYou can also take a look at [d3-random](https://github.com/d3/d3-random) for random number generator from other-than-uniform distributions.\n\n## Dependencies\n\n- d3-voronoi-map.voronoiMap\n\n## Semantic Versioning\n\nd3-voronoi-treemap attempts to follow [semantic versioning](https://semver.org) and\nbump major version only when backwards incompatible changes are released.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKcnarf%2Fd3-voronoi-treemap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKcnarf%2Fd3-voronoi-treemap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKcnarf%2Fd3-voronoi-treemap/lists"}