Envisioning LogoEnvisioning App (6.3.0)
Configuration

Quadrants

Configure the two-axis Quadrants visualization

Overview

The Quadrants visualization plots entities on a horizontal and vertical metric axis. Optional bubble sizing encodes a third metric. Entities that share the same coordinates are grouped into a cluster badge; clicking the badge expands the cluster so individual entities can be selected. Register it in the settings.visualization array:

import type { Config, Visualizations } from "@envisioning/app";

const Quadrants: Visualizations["quadrants"] = {
  type: "quadrants",
  label: { en: "Quadrants" },
  entityPageId: "technology",
  horizontal: [{ joinKey: "trl" }],
  vertical: [{ joinKey: "doi" }],
  bubble: [{ joinKey: "cost" }],
};

const settings: Config["settings"] = {
  visualization: [Quadrants],
  // ...
};

Multiple visualizations can coexist in the same project (for example, Radar and Quadrants):

visualization: [Radar, Quadrants],

Core Properties

PropertyTypeRequiredDescription
type"quadrants"YesVisualization type
labelI18nYesDisplay label
entityPageIdstringYesTarget page for entity clicks
horizontalarrayYesHorizontal (X) axis metric(s)
verticalarrayYesVertical (Y) axis metric(s)
bubblearrayNoBubble size metric(s)
settingsobjectNoVisual appearance settings
showDownloadButtonbooleanNoShow download button (default: true)
titlePathstringNoOverride entity title path from schema
toolbararrayNoCustom toolbar items
toolbarOptionsarrayNoCustom toolbar option menus

Metric Dimensions

horizontal, vertical, and bubble accept the same metric configuration shape used by the Radar:

{
  horizontal: [
    {
      label: { en: "TRL" },
      joinKey: "trl",
      scale: { type: "linear" },
    },
  ],
}

Dimension Properties

PropertyTypeDescription
labelI18nOptional override label
joinKeystringSchema join key for the metric
scaleobjectD3 scale configuration
showOptionbooleanShow in toolbar menu (default: true)
forceDomain[number, number]Override metric domain

Scale Types

scale: { type: "linear" }       // default
scale: { type: "symlog", constant: 1 }
scale: { type: "pow", exponent: 2 }
scale: { type: "sqrt" }

Each dimension requires a metric join. A non-metric join key causes a runtime error:

horizontal schema is not a metric. Check horizontal metric for quadrants visualization.
vertical schema is not a metric. Check vertical metric for quadrants visualization.
bubble schema is not a metric. Check bubble metric for quadrants visualization.

Horizontal (X Axis)

Controls where entities appear along the horizontal axis. The active metric is selected from the toolbar.

horizontal: [
  {
    label: { en: "TRL" },
    joinKey: "trl",
  },
  {
    label: { en: "Cost" },
    joinKey: "cost",
  },
],

Vertical (Y Axis)

Controls where entities appear along the vertical axis. The active metric is selected from the toolbar.

vertical: [
  {
    label: { en: "Diffusion of Innovation" },
    joinKey: "doi",
  },
  {
    label: { en: "TRL" },
    joinKey: "trl",
  },
],

Changing the horizontal or vertical metric recenters the chart zoom.


Bubble (Size)

Controls entity dot and bubble 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 (those settings are radii at the domain endpoints; radius is derived via √area so area is proportional to the value).

Cluster size

Add a virtual bubble option with joinKey: "clusterSize" (no schema join). When selected, cluster badge radius and entity bubble radius scale by the number of entities at the same coordinates:

  • Domain: [1, maxClusterSize] where maxClusterSize is the largest overlap group on the chart.
  • Range: [minClusterRadius, maxBubbleRadius] as radii at domain endpoints; cluster count maps to area between those bounds.
  • Solo entities (not in a multi-item cluster) use count 1 and stay at their metric position.
  • The cluster badge scales with group size; after opening a cluster, each exploded entity bubble uses count 1 (minimum radius) so individuals are smaller than the badge.
{
  label: { en: "Cluster size" },
  joinKey: "clusterSize",
},

Metric bubble options keep a fixed cluster badge radius (minClusterRadius) regardless of group size.


Overlapping Entities (Clusters)

Entities with identical horizontal and vertical metric values are rendered as a single cluster circle showing the count. Clicking the cluster opens an explosion layout: entities are placed on concentric rings around a close control so each can be clicked individually. Exploded entities use a fixed hit target of dotRadius + dotPadding (independent of bubble size). Ring spacing between hit areas uses maxBubbleRadius when a metric bubble option is active, or minClusterRadius when the bubble option is clusterSize; entities on each ring are equally spaced. Click the fog overlay or the close button to collapse the cluster.

SettingDefaultDescription
minClusterRadius2 × dotRadiusMinimum cluster badge radius; fixed badge size for metric bubble options; lower bound of the cluster-size scale
clusterFontSize18Font size for the count label

Chart Results

The toolbar Chart Results menu controls how discrete metricResults labels are displayed. This is session state (not config); the default is vertical axis results.

ModeDescription
Vertical axis resultsShow metricResults labels along the vertical axis
Horizontal axis resultsShow metricResults labels along the horizontal axis
Intersection resultsShow quadrant labels from intersectionSettings
NoneHide all chart result labels

Intersection results only appears when at least one quadrant label (topLeftLabel, topRightLabel, bottomLeftLabel, bottomRightLabel) resolves to non-empty text.

Axis result labels are only rendered for metrics with metricType other than "CONTINUOUS".


Visual Settings

settings: {
  color: "{collection.color.hex}",  // entity fill; default: "accent"
  dotRadius: 5,
  dotPadding: 3,
  maxBubbleRadius: 30,
  bubbleOpacity: 0.3,
  chartWidth: 1500,
  chartHeight: 1000,
  chartPadding: 20,
  showGrid: false,
  resultSettings: { /* axis result labels */ },
  verticalAxisSettings: { /* Y axis ruler */ },
  horizontalAxisSettings: { /* X axis ruler */ },
  intersectionSettings: { /* quadrant labels */ },
},

Chart Layout

SettingDefaultDescription
color"accent"Fill color (descriptor or template)
dotRadius5Base dot radius
dotPadding3Added to dotRadius for minimum bubble radius
maxBubbleRadius30Maximum bubble radius at the top of the metric domain (area-encoded)
bubbleOpacity0.3Opacity of sized bubbles
chartWidth1500Plot width in SVG user units
chartHeight1000Plot height in SVG user units
chartPadding20Inset from chart edges
showGridfalseGrid lines aligned with axis ticks

Axis Settings (verticalAxisSettings / horizontalAxisSettings)

Both axes share the same shape. Defaults apply independently per axis.

verticalAxisSettings: {
  originPosition: "center",
  showTitle: true,
  showTicks: true,
  showLine: true,
  tickStep: 1,
  showTicksLabels: "values",
  titlePosition: "outside",
  padding: 20,
  tickLabelSize: 14,
  titleSize: 18,
},
PropertyDefaultDescription
originPosition"center"Ruler line position: center, min, max, origin (uses metricOrigin), outside
showTitletrueShow metric title
showTickstrueShow tick marks
showLinetrueShow axis line
tickStep1Step between tick values
showTicksLabels"values"false, "values", or "labels" (uses metricResults with numeric fallback)
titlePosition"outside""inside" or "outside" relative to plot center
padding20Space between axis line and title or tick labels
tickLabelSize14Tick label font size
titleSize18Metric title font size

Result Settings (resultSettings)

Styles labels drawn from metricResults along the active axis (vertical or horizontal chart-results mode).

resultSettings: {
  fontSize: 36,
  fontWeight: "normal",
  textColor: "disabled",
  textOpacity: 1,
  textTranslate: 0,
},
PropertyDefaultDescription
fontSize36Label font size (number or CSS string)
fontWeight"normal"normal, light, or bold
textColor"disabled"Theme color token
textOpacity1Label opacity
textTranslate0Offset from axis (positive moves up on vertical axis)

Intersection Settings (intersectionSettings)

Labels for the four quadrants when Intersection results is selected.

intersectionSettings: {
  topLeftLabel: { en: "Explore" },
  topRightLabel: { en: "Adopt" },
  bottomLeftLabel: { en: "Assess" },
  bottomRightLabel: { en: "Scale" },
  labelPosition: "center",
  labelPadding: 24,
  labelFontSize: 36,
  labelOpacity: 1,
  labelFontWeight: "normal",
  labelColor: "disabled",
},
PropertyDefaultDescription
topLeftLabelTop-left quadrant label
topRightLabelTop-right quadrant label
bottomLeftLabelBottom-left quadrant label
bottomRightLabelBottom-right quadrant label
labelPosition"center"center, corner, or origin
labelPadding24Inset for corner and origin placement
labelFontSize36Font size
labelOpacity1Label opacity
labelFontWeight"normal"normal, light, or bold
labelColor"disabled"Theme color token

Toolbar

When horizontal, vertical, or bubble arrays are provided, the visualization renders a toolbar with:

  • Vertical scale — single-select over vertical options
  • Horizontal scale — single-select over horizontal options
  • Bubble — single-select over bubble options (when configured)
  • Chart Results — single-select for axis or intersection label display

Options with showOption: false are hidden from the menu.

Session preferences (selected indices) are stored per visualization index and default to the first horizontal option, second vertical option, first bubble option, and vertical chart results.


Zoom and Navigation

The chart supports pan and zoom. Selecting an entity via URL or click zooms to that entity. Changing axis metrics recenters the view. Entity selection uses slug-first matching (same as Radar and cards).


Complete Example

import type { Visualizations } from "@envisioning/app";

const metricOptions = [
  { label: { en: "TRL" }, joinKey: "trl" },
  { label: { en: "Diffusion of Innovation" }, joinKey: "doi" },
  { label: { en: "Cost" }, joinKey: "cost" },
] as const;

export const Quadrants: Visualizations["quadrants"] = {
  type: "quadrants",
  label: { en: "Quadrants", pt: "Quadrantes" },
  entityPageId: "technology",
  showDownloadButton: true,
  settings: {
    color: "{collection.color.hex}",
    dotRadius: 6,
    maxBubbleRadius: 40,
    bubbleOpacity: 0.5,
    chartPadding: 150,
    resultSettings: {
      fontSize: 48,
      fontWeight: "bold",
      textColor: "border",
      textTranslate: 30,
    },
    intersectionSettings: {
      topLeftLabel: { en: "Explore", pt: "Explorar" },
      topRightLabel: { en: "Adopt", pt: "Adotar" },
      bottomLeftLabel: { en: "Assess", pt: "Avaliar" },
      bottomRightLabel: { en: "Scale", pt: "Escalar" },
      labelPosition: "center",
      labelFontSize: 36,
      labelPadding: 120,
    },
    verticalAxisSettings: {
      originPosition: "outside",
      showTicksLabels: "values",
      titlePosition: "outside",
      padding: 30,
      tickLabelSize: 18,
      titleSize: 24,
    },
    horizontalAxisSettings: {
      originPosition: "outside",
      showTicksLabels: "values",
      titlePosition: "outside",
      padding: 30,
      tickLabelSize: 18,
      titleSize: 24,
    },
  },
  horizontal: [...metricOptions],
  vertical: [...metricOptions],
  bubble: [...metricOptions],
};

Validation

The configuration validates that:

  1. entityPageId exists in the pages array
  2. All joinKey values in horizontal, vertical, and bubble exist in the schema joins

If validation fails:

Page "technology" not found in pages. Check visualization: quadrants
Join key "trl" not found in the schema. Check: quadrants - horizontal, joinKey: trl

On this page