Skip to content

Packages

Treemaps and heatmaps

The general-purpose charts in the family, on the same engine.

What Is in the Package

@ortex-charts/viz holds the general-purpose charts a financial data product needs alongside its price charts: a category chart for bars and columns, a treemap, a heatmap, and export helpers for PNG and CSV. They run on the same canvas layer, follow the same theme tokens and share one animation frame with everything else on the page.

npm install @ortex-charts/viz

Each component follows its container, is device-pixel-ratio aware, has an optional built-in tooltip, and is created and disposed the same way:

import { createTreemap, createHeatmap, createCategoryChart } from "@ortex-charts/viz";

const chart = createTreemap(el, { theme: "dark", data });
chart.applyOptions({ colorMode: "change" });
chart.setTheme("light");
chart.resize(900, 500);
chart.flush();      // draw synchronously
chart.remove();
Treemap and heatmap@ortex-charts/viz
Loading treemap and heatmap
The general-purpose charts in the family: a sector treemap and a returns heatmap on the same engine.

Open this example with its source

Treemap

A treemap sizes rectangles by value and colors them by change, which is the standard way to show a universe of instruments at once.

import { createTreemap, type TreemapNode } from "@ortex-charts/viz";

const data: TreemapNode = {
  name: "S&P 500",
  children: [
    {
      name: "Technology",
      children: [
        { name: "AAPL", value: 3_100_000, change: 1.42 },
        { name: "MSFT", value: 2_900_000, change: -0.63 },
      ],
    },
    {
      name: "Financials",
      children: [{ name: "JPM", value: 620_000, change: 0.28 }],
    },
  ],
};

const treemap = createTreemap(el, {
  theme: "dark",
  data,
  colorMode: "change",
  changeDomain: "auto",
  valueFormat: { type: "compact", precision: 1 },
  changeFormat: { type: "percent", precision: 2 },
  headers: true,
  breadcrumb: true,
  drillDown: true,
  onClick: (hit) => openInstrument(hit.data.name),
});

A node has name, an optional value for leaves, an optional change that drives the diverging color scale, an optional explicit color inherited by descendants, and children. Parents are sized by the sum of their leaves, so only the leaves need values.

Option Default What it does
colorMode "auto" auto uses an explicit color, else the change scale, else the group palette color. explicit, change and group force one of them.
changeDomain "auto" Domain of the diverging scale; auto is symmetric about zero over the visible leaves.
changeColors theme [low, neutral, high]; defaults to theme.down, theme.grid, theme.up.
valueFormat, changeFormat Number formatting for the labels and the tooltip.
paddingInner, paddingOuter Gaps between and around rectangles.
headers, headerHeight true Header strips above groups.
breadcrumb true Path strip above the map while zoomed in.
labels, minFontSize, maxFontSize true Names and values inside leaves when they fit.
drillDown true Click a group to zoom in; click the breadcrumb to zoom out.
treemap.setData(nextRoot);
treemap.zoomTo(node);
treemap.zoomOut(1);
treemap.currentRoot();
treemap.getPath();       // TreemapNode[] from the full root to the current one
treemap.getLayout();     // the laid-out tree in CSS pixels

layoutTreemap, treemapLeaves and findPath are exported for hosts that want the layout without the canvas — for a server-rendered image, a test, or an accessible table alternative.

Heatmap

A grid of rows by columns with a sequential or diverging color scale, which is what a returns calendar, a correlation matrix or a factor exposure grid wants.

import { createHeatmap } from "@ortex-charts/viz";

const heatmap = createHeatmap(el, {
  theme: "light",
  rows: ["2021", "2022", "2023", "2024", "2025"],
  columns: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
  values: [
    [1.2, -0.4, 2.8, 0.1, -1.9, 3.2],
    [-2.1, 0.8, 1.1, NaN, 0.4, -0.7],
    // …
  ],
  scale: { type: "diverging", domain: "auto", center: 0 },
  format: { type: "percent", precision: 1 },
  cellLabels: true,
  legend: true,
  onClick: (hit) => drillInto(hit.rowLabel, hit.columnLabel),
});

values is row-major: values[row][column]. NaN is an empty cell and is drawn in emptyColor rather than at the bottom of the scale, which matters for a calendar with missing months.

Option Default What it does
scale.type "diverging" sequential or diverging.
scale.domain "auto" [min, max], or derived from the finite values; symmetric about center when diverging.
scale.center 0 Center of a diverging scale.
scale.colors theme Two colors for sequential, three for diverging.
format percent, 1 decimal Cell and tooltip formatting.
cellLabels true Print the value in the cell when it fits.
cellGap 1 Pixels between cells.
rowLabels, columnLabels true Axis labels.
columnLabelPosition "top" top or bottom.
maxLabelWidth 140 Cap on a label footprint in pixels.
legend true Color bar under the grid.
emptyColor a faint tint Fill for NaN cells.
heatmap.setData({ rows, columns, values });
heatmap.colorFor(1.4);        // the color a value would get, for a host-drawn legend

resolveHeatmapDomain and createColorScale are exported for the same reason: a host that wants to color a table cell to match the heatmap can use exactly the same scale.

Category Chart

Bars and columns over a categorical axis, stacked or grouped, horizontal or vertical.

import { createCategoryChart } from "@ortex-charts/viz";

const chart = createCategoryChart(el, {
  theme: "dark",
  orientation: "horizontal",
  categories: ["Energy", "Financials", "Healthcare", "Technology", "Utilities"],
  series: [
    { key: "long", title: "Long", color: "#22C08A", data: [12, 34, 21, 55, 8] },
    { key: "short", title: "Short", color: "#EF4E5A", data: [-4, -12, -6, -19, -2] },
  ],
  stacked: true,
  baseline: 0,
  colorBySign: false,
  valueLabels: true,
  legend: true,
  sortBy: "desc",
  valueAxis: { position: "bottom", format: { type: "compact", precision: 1 }, gridlines: true, visible: true },
  onClick: (hit) => filterBy(hit.category),
});

chart.setData({ categories, series });

orientation: "vertical" draws columns and "horizontal" draws bars. colorBySign colors each bar by which side of baseline it falls on, using the theme up and down colors, which is the fastest way to a readable contribution chart. sortBy orders categories by their total across series without changing the underlying arrays, and CategoryHit.categoryIndex is the index into your original categories, not into the displayed order.

Export

import { canvasToPNG, downloadPNG, downloadCSV, rowsToCSV, composeCanvases } from "@ortex-charts/viz";

await downloadPNG(chartCanvas, "sectors.png", { scale: 2, background: "#0E1218" });

const csv = rowsToCSV(rows, ["symbol", { key: "change", label: "1D %" }]);
downloadCSV(rows, "universe.csv", ["symbol", "value", "change"]);

const combined = composeCanvases([topCanvas, bottomCanvas], "#0E1218");

canvasToPNG returns a Blob for hosts that want to upload rather than download, and composeCanvases stacks several canvases into one image, which is how a multi-pane screenshot is assembled.

These helpers are in viz rather than in core because they are DOM download plumbing rather than chart engine. A financial chart's own screenshot is chart.takeScreenshot(), which returns a canvas you can pass straight to canvasToPNG.

Shared Options and Methods

Every component takes theme, width, height, tooltip and padding, and exposes:

component.root;                       // the container div it created
component.getTheme();
component.getOptions();               // readonly
component.setTheme(theme);            // "dark", "light", or a Theme object
component.applyOptions(patch);        // deeply partial
component.resize(width, height);
component.invalidate();               // schedule a redraw
component.flush();                    // draw now
component.remove();

Leaving width and height unset makes the component follow its container, which is the usual choice; setting them fixes the size, which is what an export path wants.

What Is Not Here

@ortex-charts/viz is three chart types, not a general charting library. There is no scatter or bubble chart, no pie or donut, no radar, no sankey, no gauge, no geographic map and no 3D. Apache ECharts has 20 or more chart types and is a reasonable thing to use alongside this package if you need them.

What viz is for is the small set of general charts that have to look like the price chart, share its theme, and cost nothing extra in the bundle because the engine is already there.