@gramex/radar
Version:
A radial beeswarm or dot plot.
262 lines (189 loc) • 8.09 kB
Markdown
# /radar
A radial beeswarm or dot plot.
## Example
Given this [100 most popular movies on IMDb](docs/imdb.csv ":ignore"):
[](docs/imdb.csv ":ignore")
... we can render the following radar:
[](docs/playground.html ":include height=420px")
## Installation
Install via `npm`:
```bash
npm install /radar@1
```
Use locally as an ES module:
```html
<script type="module">
import { radar } from "./node_modules/@gramex/radar/dist/radar.js";
</script>
```
Use locally as a script:
```html
<script src="./node_modules/@gramex/radar/dist/radar.min.js"></script>
<script>
gramex.radar(...)
</script>
```
Use via CDN as an ES Module:
```html
<script type="module">
import { radar } from "https://cdn.jsdelivr.net/npm/@gramex/radar@1";
</script>
```
Use via CDN as a script:
```html
<script src="https://cdn.jsdelivr.net/npm/@gramex/radar@1/dist/radar.min.js"></script>
<script>
gramex.radar(...)
</script>
```
## Data is a list of levels and spokes
The data is a list of rows containing an ordered "level" category (going outwards) and an unordered "spoke" category . Each row is an object with keys for each column. For example:
```js
const data = [
{ level: "low", spoke: "blue" },
{ level: "low", spoke: "orange" },
{ level: "low", spoke: "green" },
{ level: "medium", spoke: "blue" },
{ level: "medium", spoke: "orange" },
{ level: "medium", spoke: "green" },
{ level: "high", spoke: "blue" },
{ level: "high", spoke: "orange" },
{ level: "high", spoke: "green" },
];
```
[](docs/data.html ":include height=420px")
[See how to use radar](docs/data.html ":include :type=code")
Calling `radar(el, { data })` will render the radar. You need to style the output.
## Specify level and spoke columns
Use `level` and `spoke` parameters to customize the columns used for levels and spokes. For example, this
[employees data](docs/employees.csv ":ignore") has:
| team | band |
| ----------- | ------ |
| Analytics | Band 1 |
| Consulting | Band 2 |
| Design | Band 3 |
| Engineering | Band 4 |
| ... | ... |
We use the `level` and `spoke` parameters to specify the columns:
```js
const graph = radar("#radar", {
data,
level: (d) => d.band.replace(/Band /, ""),
spoke: (d) => d.team,
...
});
```
The radar automatically adjusts the
[](docs/employees.html ":include height=420px")
[See how to specify level and spoke columns](docs/employees.html ":include :type=code")
## Re-order levels and spokes
Radar auto-extracts levels and spokes from data. Use `levels` and `spokes` to:
- Show only specific levels and spokes (even if they don't exist in the data)
- Re-order levels and spokes
For example:
```js
const graph = radar("#radar", {
data,
// Show only the top 3 levels, in descending order
levels: ["6", "5", "4"],
// Show these levels in order, even though Legal doesn't exist
spokes: ["Design", "Consulting", "Engineering", "Legal"],
...
});
```
You can specificy `levels` and `spokes` dynamically with a function `Map(key, count) => [...keys]`. For example:
```js
const graph = radar("#radar", {
data,
// Sort levels in reverse (e.g. "6", "5", "4", ... "1")
levels: (counter) => [...counter.keys()].sort(d3.descending),
// Sort spokes in descending order of count, i.e. largest first
spokes: (counter) => d3.sort([...counter.keys()], d => -counter.get(d)),
...
});
```
[](docs/reorder.html ":include height=420px")
[See how to customize levels and spokes](docs/reorder.html ":include :type=code")
## Resize levels and spokes
Radar distributes levels and spokes evenly within the container circle. Use `levelScale` and `spokeScale` to:
- Create spacing between levels or spokes
- Give more space to specific levels or spokes
For example:
```js
// Start and end radius in SVG units (pixels)
const levelRange = [[0, 60], [66, 120], [125, 140], [145, 160], [165, 180], [185, 200]];
// Start and end angle in degrees
const spokeRange = [[180, 210], [210, 240], [240, 255], [255, 310], [310, 330], [330, 360]]
const graph = radar("#radar", {
data,
levelScale: (level, index) => levelRange[index],
spokeScale: (spoke, index) => spokeRange[index],
...
});
```
You can also specify the center of the radar using `cx` and `cy`. It defaults to `width / 2` and `height / 2`.
```js
const graph = radar("#radar", {
data,
cx: 100,
cy: 100,
...
});
```
Use `graph.r` to get the maximum non-overlapping radius of the nodes.
[](docs/resize.html ":include height=220px")
[See how to resize levels and spokes](docs/resize.html ":include :type=code")
## Style the radar
The returned object has the following D3 selections:
- `cells`: Arc paths for each level, spoke segment. (Used to style the background of the radar). The data includes:
- `level`: The level
- `spoke`: The spoke
- `levelIndex`: The index of the level (0, 1, 2, ...)
- `spokeIndex`: The index of the spoke (0, 1, 2, ...)
- `r0`: The inner radius of the spoke
- `r1`: The outer radius of the spoke
- `a0`: The start angle of the spoke in radians
- `a1`: The end angle of the spoke in radians
- `n`: Number of data points in this cell
- `data`: All data elements for this cell (i.e. level and spoke combination). Absent if n == 0
- `nodes`: Circles for each data element. The data includes:
- `x`: The x-coordinate of the node
- `y`: The y-coordinate of the node
- `levelLabels`: Text labels for each level. The data includes:
- `level`: The level name / label
- `levelIndex`: The index of the level (0, 1, 2, ...)
- `r0`: The inner radius of the spoke
- `r1`: The outer radius of the spoke
- `spokeLabels`: Text labels for each spoke. The data includes:
- `spoke`: The spoke name / label
- `spokeIndex`: The index of the spoke (0, 1, 2, ...)
- `a0`: The start angle of the spoke in radians
- `a1`: The end angle of the spoke in radians
You can style these using D3 selections. For example:
```js
// Color empty background cells pink, and filled cells white
graph.cells.attr("fill", (d) => (d.n ? "white" : "pink"));
// Color nodes with see-through black. Give them a bit more than the maximum non-overlapping size
graph.nodes.attr("fill", "rgba(0,0,0,0.2)").attr("r", graph.r * 1.5);
// Make labels bigger and red
graph.levelLabels.attr("font-size", 12).attr("fill", "red");
graph.spokeLabels.attr("font-size", 12).attr("fill", "red");
```
[](docs/style.html ":include height=420px")
[See how to style the radar](docs/style.html ":include :type=code")
## Add tooltips
You can use [Bootstrap tooltips](https://getbootstrap.com/docs/5.3/components/tooltips/).
1. Add a `data-bs-toggle="tooltip" title="..."` attribute to each feature using `update`
2. Call `new bootstrap.Tooltip(element, {selector: '[data-bs-toggle="tooltip"]'})` to initialize tooltips
[](docs/imdb.html ":include height=420px")
[See how to add tooltips](docs/imdb.html ":include :type=code")
## Bring your own D3
If you already have D3 loaded, or want to use a specific version / instance of D3, pass it to `radar(el, { d3 })`:
## API
[See API documentation](docs/api.md ":include :type=markdown")
## Release notes
- 1.0.0: 24 Mar 2024. Initial release
## Authors
- Anand S <s.anand.com>
## License
[MIT](https://spdx.org/licenses/MIT.html)