Bubble Packing
Configure the circle-packed Bubble Packing visualization
Overview
The Bubble Packing visualization displays entities as circles packed into clusters. Entity size is driven by a metric (bubble), and entities can be grouped into separate packed regions (group). Register it in the settings.visualization array:
import type { Config, Visualizations } from "@envisioning/app";
const BubblePacking: Visualizations["bubblePacking"] = {
type: "bubblePacking",
label: { en: "Bubble packing" },
entityPageId: "technology",
bubble: [{ joinKey: "trl" }],
group: [{ joinKey: "collection" }],
};
const settings: Config["settings"] = {
visualization: [BubblePacking],
// ...
};Multiple visualizations can coexist in the same project (for example, Radar and Bubble Packing):
visualization: [Radar, BubblePacking],Core Properties
| Property | Type | Required | Description |
|---|---|---|---|
type | "bubblePacking" | Yes | Visualization type |
label | I18n | Yes | Display label |
entityPageId | string | Yes | Target page for entity clicks |
bubble | array | No | Bubble size metric(s) |
group | array | No | Grouping metric(s) |
settings | object | No | Visual appearance settings |
preferences | object | No | User preference toggles |
showDownloadButton | boolean | No | Show download button (default: true) |
titlePath | string | No | Override entity title path from schema |
toolbar | array | No | Custom toolbar items |
toolbarOptions | array | No | Custom toolbar option menus |
Metric Dimensions
bubble and group accept the same metric configuration shape used by the Radar:
{
bubble: [
{
label: { en: "TRL" },
joinKey: "trl",
scale: { type: "linear" },
},
],
}Dimension Properties
| Property | Type | Description |
|---|---|---|
label | I18n | Optional override label |
joinKey | string | Schema join key for the metric |
scale | object | D3 scale configuration |
showOption | boolean | Show in toolbar menu (default: true) |
forceDomain | [number, number] | Override metric domain |
color | string | Color descriptor or template for entity fill |
Scale Types
scale: { type: "linear" } // default
scale: { type: "symlog", constant: 1 }
scale: { type: "pow", exponent: 2 }
scale: { type: "sqrt" }Bubble (Size)
Controls entity circle radius. The active metric is selected from the toolbar. When no bubble option is configured, all entities use dotRadius.
bubble: [
{
label: { en: "TRL" },
joinKey: "trl",
},
{
label: { en: "Cost" },
joinKey: "cost",
},
],The metric value is mapped from the schema domain to circle area between dotRadius + dotPadding and maxBubbleRadius (radii at domain endpoints; area is proportional to the value).
Group (Clusters)
Controls how entities are clustered. The active grouping is selected from the toolbar.
group: [
{
label: { en: "Collection" },
joinKey: "collection",
color: "{collection.color.hex}",
},
{
label: { en: "TRL" },
joinKey: "trl",
},
{
label: { en: "Favorites" },
joinKey: "favorites",
},
{
label: { en: "None" },
joinKey: "", // No grouping
},
],joinKey | Behavior |
|---|---|
| Schema join key | Groups entities by that join's value |
"favorites" | Splits into favorites vs non-favorites (session state) |
"" | No grouping — all entities in one cluster |
Layout Modes
Layout is controlled by the singleBlock preference (see below).
Cluster mode (singleBlock: false)
Entities are bucketed by the active group, each bucket is packed locally, then bucket-enclosing circles are packed globally. groupPadding adds space between sibling groups.
Single-block mode (singleBlock: true)
All entities are packed into one cluster. Same-group bubbles stay cohesive via a centroid attraction force, and groupPadding is expressed as whitespace between bubbles of different groups rather than gaps between separate packed regions.
Preferences
preferences: {
singleBlock: {
default: true,
showOption: true,
label: { en: "Single block" },
},
},| Preference | Default | Description |
|---|---|---|
singleBlock | false | Pack all entities in one cluster with inter-group whitespace |
Set showOption: false to hide a preference from the toolbar settings menu.
Visual Settings
settings: {
color: "{collection.color.hex}", // entity fill; default: "accent"
itemPadding: 2, // space between sibling items (SVG units)
groupPadding: 8, // space between sibling groups (SVG units)
maxBubbleRadius: 30, // upper bound of bubble size scale
bubbleOpacity: 0.3, // opacity of metric-sized bubbles
dotRadius: 5, // base dot radius
dotPadding: 3, // added to dotRadius for minimum bubble radius
},| Setting | Default | Description |
|---|---|---|
color | "accent" | Fill color (descriptor or template) |
itemPadding | 2 | Extra space between sibling circles |
groupPadding | 8 | Extra space between groups (meaning depends on layout mode) |
maxBubbleRadius | 30 | Maximum bubble radius at the top of the metric domain (area-encoded) |
bubbleOpacity | 0.3 | Opacity of sized bubbles |
dotRadius | 5 | Base dot radius |
dotPadding | 3 | Added to dotRadius for minimum bubble radius |
Toolbar
When bubble or group arrays are provided, the visualization renders a toolbar with:
- Group by — single-select over
groupoptions - Bubble — single-select over
bubbleoptions - Settings — multi-select for user preferences (
singleBlock)
Options with showOption: false are hidden from the menu.
Complete Example
import type { Visualizations } from "@envisioning/app";
export const BubblePacking: Visualizations["bubblePacking"] = {
type: "bubblePacking",
label: { en: "Bubble packing", pt: "Empacotamento de bolhas" },
entityPageId: "technology",
showDownloadButton: true,
settings: {
color: "{collection.color.hex}",
itemPadding: 2,
groupPadding: 20,
maxBubbleRadius: 70,
bubbleOpacity: 0.5,
dotRadius: 6,
},
preferences: {
singleBlock: { default: true },
},
bubble: [
{ label: { en: "TRL" }, joinKey: "trl" },
{ label: { en: "Cost" }, joinKey: "cost" },
],
group: [
{
label: { en: "Collection" },
joinKey: "collection",
color: "{collection.color.hex}",
},
{ label: { en: "TRL" }, joinKey: "trl" },
{ label: { en: "Favorites" }, joinKey: "favorites" },
{ label: { en: "None" }, joinKey: "" },
],
};Validation
The configuration validates that:
entityPageIdexists in the pages array- All
joinKeyvalues inbubbleandgroupexist in the schema joins (except virtual group keys)
Virtual group join keys that bypass schema validation:
joinKey | Meaning |
|---|---|
"favorites" | Group by session favorites |
"" | No grouping |
If validation fails:
Page "technology" not found in pages. Check visualization: bubblePacking
Join key "trl" not found in the schema. Check: bubblePacking - bubble, joinKey: trlThe bubble dimension requires a metric join. A non-metric join key causes a runtime error:
bubble schema is not a metric. Check bubble metric for bubblePacking visualization.