Home | Gallery

Interactive & Ray Traced Data Visualization

Last updated Feb 21, 2024
Ray-traced data visualization showing a hex-binned histogram of tornados in the United States.
Ray-traced data visualization showing a hex-binned histogram of tornados in the United States.

See the gallery for a selection of visualizations created with the MorphCharts raytrace renderer.

Contents

  1. Introduction
  2. Gallery
  3. Features
    1. Renderers
    2. Layout
    3. Transitions
    4. Interaction
    5. Axes
    6. Data
    7. Background Images
    8. Labels
    9. Virtual Reality
  4. Getting Started
    1. Coordinates
    2. Initialization
    3. Layouts
      1. Scatter Plot
      2. Bar Chart
      3. Stack Chart (Count)
      4. Stack Chart (Sum)
      5. Line Chart
      6. Squarified Treemap
    4. Facets
      1. Wrap
      2. Cross-Facet
      3. Layout Per Facet
    5. Renderers
    6. Interaction
      1. Selection
      2. Filtering
    7. Palettes
    8. Axes
    9. Labels
    10. Transitions
    11. Fonts
    12. Data
      1. Tables
      2. Arrays
    13. Ray Tracing
      1. Materials
      2. Unit Types
      3. Motion Blur
    14. Debugging
  5. Apps
  6. About

Introduction

MorphCharts is a low-level JavaScript library for interactive and ray traced data visualization in both 2D and 3D.

Features

Renderers

Multiple renderers are provided:

The basic and advanced renderers are designed for interactive data visualization, whereas the raytrace renderer is designed for creating high-quality images and videos.

The latest Chrome 113 now supports WebGPU. In order to use this renderer with Edge, download Edge Canary and enable WebGPU in the experimental features via edge://flags. See https://caniuse.com/webgpu for support status.

Layout

Chart layouts are provided for:

Layouts can be combined to create new chart types, for example a node-link graph can be created by combining a scatter plot (for the nodes) and a line chart (for the edges).

Helper functions are provided to support faceting layouts.

Transitions

Visualizations can specify a pair of layouts such that they can be smoothly animated. This helps a user maintain context while switching layouts, and facilitates building animated data stories.

Data points can transition simultaneously, or in a custom order to create "staggered" transitions.

Unit histograms of US Tornados by strength, showing animated transitions between binning by month,
            hour and year.
Unit histograms of US Tornados by strength, showing animated transitions between binning by month, hour and year.

Interaction

A default interaction manager is provided for zooming, panning, and rotating the view. Mouse, touch, stylus, keyboard and Surface Dial are supported.

Selections can be made from the axes or with lasso gestures.

Alt-azimuth and arc-ball cameras are provided.

Axes

Helper functions are provided for working with 2D and 3D axes. Multiple axes can be used to support faceted views.

Selections can be made using grid divisions along the axes, using grid cells, or using labels.

3D axes dynamically adapt the text orientation and edge visibility to the viewing angle.

Unit histograms of Titanic passengers by gender and ticket class and colored by strength, rotating
            to show dynamic axes.
Unit histograms of Titanic passengers by gender and ticket class and colored by strength, rotating to show dynamic axes.

Data

Helper functions are provided for working with delimited (CSV) text files, however clients are free to load data from any data source.

A data-table abstraction is provided for:

Background Images

Background images, such as maps, can be added to provide context. Images can be rectangular or spherical.

World population with flat background image.
World population with flat background image.
World population with spherical background image.
World population with spherical background image.

Labels

Labels can be added individually or in groups for higher performance.

Virtual Reality

Support for immersive experiences with virtual reality headsets and controllers is supported via WebXR in the basic renderer.

Stereo

Stereo rendering is supported in the basic renderer with left, right, split-screen and anaglyph modes.

Buckminsterfullerine (C60) molecule in anaglyph stereo.
Buckminsterfullerine (C60) molecule in anaglyph stereo.

Getting Started

MoprhCharts is a low-level JavaScript library. The recommended way to consume the library is using TypeScript and importing the library from npm. The TypeScript declaration files will provide IntelliSense in development tools such as Visual Studio Code.

The following examples are presented as plain JavaScript with an ES6 import of the library from a CDN, so they can be run directly without a bundler. Note that for the purposes of simplicity, the samples occasionally use different types from the TypeScript declaration files (for example, Array instead of glMatrix.vec3).

Coordinates

MorphCharts uses right-hand coordinates, so if the x-axis is to the right and the y-axis is up, the z-axis is towards the viewer. 2D layouts and axes use the x-axis and y-axis. 3D layouts and axes add the z-axis.

Initialization

The key classes required to create a visualization are the Core, a renderer (e.g. BasicRenderer), and a TransitionBuffer.

A TransitionBuffer contains information for a specific number of "units". Each unit could, for example correspond to a record in a tabular dataset. The TransitionBuffer has a currentBuffer and previousBuffer, each of which can be updated with independent positions, sizes, orientations, colors etc for each unit, allowing an animated transition between views. This helps users maintain context and enables animated data stories.

A renderer creates an HTML Canvas. To place this canvas in a specifc HTML Element, use the Core options container parameter. The size can be specified either in the renderer width and height options, or on the HTML Element container itself.

Minimal initialization for 2D sheet.
Minimal initialization for 2D sheet.

Try it

Minimal initialization for 2D sheet, using a container of specified size.

If no container is passed to the Core, the renderer will add the canvas to the HTML Document and use the available space. In the following example, a style is added to ensure the the height is 100%.

Minimal initialization for 2D sheet, filling the page.

Layouts

The following examples render simple procedural data using different layouts and the basic renderer.

A layout is used to update the TransitionBuffer. Each layout has a layout() and update() method which specify the buffer to use, an array of ids (which can in be a specific order, or a subset of the TransitionBuffer's ids for faceted layouts), and a set of options. layout() is used purely for calculating layout-related properties. update() is used to update the GPU buffer, and includes any non-layout related properties such as color, selection etc. This allows these properties to be updated without re-calculating the layout.

layout() measures a set of bounds for each axis in the same units as the data (model units). update() will normalize these bounds to the range [0,1], such that the longest dimension will be unit length. By default, update() will use the bounds measured in layout(), however they can also be specified explicitly in the update() options. This allows, for example alignment with specific ranges of axes, or with other layouts. A modelPosition vector, scalar modelScale, and modelRotation quaternion is then applied by the Core.

Scatter Plot

Simple 3D scatter plot with spheres sized and colored by a scaled random value.
Simple 3D scatter plot with spheres sized and colored by a scaled random value.

Try it

Simple 3D scatter plot with spheres sized and colored by a scaled random value.

Bar Chart

Simple 3D bar chart with cylinders sized and colored by a scaled random value.
Simple 3D bar chart with cylinders sized and colored by a scaled random value.

Try it

Simple 3D bar chart with cylinders sized and colored by a scaled random value.

Stack Chart (Count)

Simple 3D histogram stack chart with blocks colored by a scaled random value.
Simple 3D histogram stack chart with blocks colored by a scaled random value.

Try it

Simple 3D histogram stack chart with blocks colored by a scaled random value.

Stack Chart (Sum)

Simple 3D stack chart with blocks sized and colored by a scaled random value.
Simple 3D stack chart with blocks sized and colored by a scaled random value.

Try it

Simple 3D stack chart with blocks sized and colored by a scaled random value.
Groups

Line Chart

Line charts are created using multiple cylindrical line segments.

Simple 3D line chart using cylinders colored by line.
Simple 3D line chart using cylinders colored by line.

Try it

Simple 3D line chart using cylinders colored by line.

Squarified Treemap

Simple 3D squarified treemap with blocks colored and sized by a scaled random value.
Simple 3D squarified treemap with blocks colored and sized by a scaled random value.

Try it

Simple 3D squarified treemap with blocks colored and sized by a scaled random value.

Facets

Charts can be faceted by providing a set of facet ids and layout offsets.

Helper functions are provided for binning and layout (wrapped or 1D, 2D or 3D grid layout).

Wrap

Scatter plot faceted and wrapped by x-value.
Scatter plot faceted and wrapped by x-value.

Try it

Scatter plot faceted and wrapped by x-value.

Cross-Facet

Scatter plot cross-faceted by x-value and y-value.
Scatter plot cross-faceted by x-value and y-value.

Try it

Scatter plot cross-faceted by x-value and y-value.

Layout Per Facet

If faceting is intended to alter the layout (e.g. for stacks, treemaps etc), layout can be called per facet.

Layouts will track the maximum dimensions across multiple layout() calls, after calling resetCumulativeLayoutBounds(). The cumulative bounds are then available in [min,max]CumulativeLayoutBounds[X,Y,Z]. Bounds can be specified manually, as in this example.

Sheet chart cross-faceted by x-value and y-value.
Sheet chart cross-faceted by x-value and y-value.

Try it

Sheet chart cross-faceted by x-value and y-value.

Renderers

Renderers are hot-swappable, but not all features are available in all renderers. For example, the Cartesian2dAxes and Cartesian3dAxes are currently only supported in the basic and advanced renderers, so axes must currently be drawn manually for the raytrace renderer.

Basic renderer.
Basic renderer.
Advanced renderer with shadows.
Advanced renderer with shadows.
Raytrace renderer with metal material.
Raytrace renderer with metal material.

Try it

Switching renderers.

Interaction

A default MorphCharts.Input.Manager processes input from touch, keyboard, mouse, mousewheel, stylus, Surface Dial, and VR controllers.

Selection

Filtering

Palettes

The basic and advanced renderers use palettes for applying color to units. A palette is simply an array of RGBA values in the range [0,255]. Helper functions are provided for creating palettes, for example by interpolating between RBG or HSV values, or by resampling a set of standard palettes.

Axes

Cartesian2dAxes and Cartesian3dAxes are provided for 2D and 3D charts respectively. The labels are not billboarded, but support arbitrary viewing directions by flipping their orientation.

A renderer defines a set of previousAxes and a set of currentAxes, such that a different set of axes can be defined for the renderer's TransitionBuffer.previousBuffer and TransitionBuffer.currentBuffer. The relevant axes can then be shown by setting therenderer's axesVisibility to AxesVisibility.previous,AxesVisibility.current, or AxesVisibility.none. They can be flipped by calling renderer.swapAxes().

Axes are not automatically aligned to chart layouts, but instead require the relevant coordinate space to the specified using a set of bounds. Typically the calculated layout bounds can be used to align the axes with the layout, or a manual set of bounds can be used to align the layout with the axes.

Labels

Labels can be added individually as a Label or in groups using a LabelSet.

Similarly to axes and chart layouts, a LabelSet can be aligned by specifying a set of bounds in an arbitrary coordinate space. The allows, for example the same data values used for the layouts to be used to position labels in a LabelSet.

Transitions

Animation can be used to transition between chart layouts, with or without staggering.

The TransitionBuffer supports animated transitions by providing a currentBuffer and previousBuffer object. The renderer's transitionTime property, a value in the range [0,1] interpolates between these two buffers. The buffers can be flipped by calling the swap() method on the TransitionBuffer.

Staggering can be applied during the layout's update pass using IVertexOptions.staggerOrders, which accepts an array of values between [0,1]. If values outside the range [0,1] are available in an existing array, the min and max can be passed using minStaggerOrder and maxStaggerOrder respectively to allow the existing array to be normalized. The order can also be reversed using the Boolean property staggerOrderReverse. If no values are passed, the data order is used for the stagger order. A single value can be used by setting IVertexOptions.staggerOrder to a number in the range [0,1].

Animated transition between layouts.
Animated transition between layouts.

Try it

Animated transition between layouts.

Transitions and Filtering

Fonts

Text is drawn using a dynamically generated SDF (signed distance field) font.

The default font can be configured using the constructor options for the Core. For example, to increase the quality of the default font, use the following option:

// High-quality SDF font
fontRasterizerOptions: {
    fontAtlas: new MorphCharts.FontAtlas(2048, 2048),
    fontSize: 192,
    border: 24,
    fontFamily: "\"segoe ui semibold\", sans-serif",
    fontWeight: "normal",
    fontStyle: "normal",
    baseline: "alphabetic",
    maxDistance: 64,
    edgeValue: 0xc0,
},

Data

There are two main ways to work with data:

Tables

The Table class provides a convenient way to work with tablular datasets. Data is typically loaded from comma-delimited (.csv) files. Column datatypes can be inferred using a helper class, or specified explicitly. The Table class will create a set of JavaScript Float64Arrays, the values of which depend on each column's MorphCharts.ColumnType.

  • ColumnType.float (1) and ColumnType.integer (2) columns create an array with the column values.
  • ColumnType.string (4) columns create an array of indices into an array of distinctStrings for each column.
  • ColumnType.date (4) columns create an array of JavaScript Date timestamps, defined as time in elapsed milliseconds from midnight at the beginning of January 1, 1970.

These arrays can then be passed to the Layout classes, and properties such as minValue and maxValue used for axes.

Loading data from csv file.
Loading data from csv file.

Try it

Loading data from csv file.

In order to work with a subset of the Table, create a Filter. When a Table is initially created, a defailt Filter called "all" is created for the entire table.

When working with a subset of the data, there is always a choice of using the data range from either the subset or the entire table, such as for the axes and layout bounds, colors, and sizes etc.

To maintain the original layout after filtering the data, use the entire Table for the Layout class Layout and the Filter for the Layout class Update.

Maintaining table layout with filter.
Maintaining table layout with filter.

Try it

Maintaining table layout with filter.
Using filter layout.
Using filter layout.

Try it

Using filter layout.

Arrays

Arrays can be used as an alternative to Tables, but require additional code. When creating a TransitionBuffer from an array, the ids should be a contiguous list of integers starting at 0 (the Table class creates these automatically). This allows a filtered subset of ids to be used with Layout classes, along with additional, unfiltered data arrays.

Ray Tracing

Materials

Whereas the basic and advanced renderers only support color, the raytrace renderer also supports materials. This image shows (from left to right) LambertianMaterial, GlossyMaterial, MetalMaterial (fuzz: 0), MetalMaterial (fuzz: 0.5) and DielectricMaterial materials respectively.

Raytrace renderer material sample using spheres.
Raytrace renderer material sample using spheres.

Try it

Raytrace renderer material sample using spheres.

Colored Glass

Isotropic Materials

Unit Types

The raytrace renderer also supports Signed Distance Field unit types, which can be used to add rounded edges.

Raytrace renderer material sample using cylinders with rounded edges.
Raytrace renderer material sample using cylinders with rounded edges.

Motion Blur

The raytrace renderer also supports motion blur.

Debugging

Information is written to the console according to the configured logging level. For more verbose logging, set:

core.config.logLevel = MorphCharts.LogLevel.debug;

In addition, interactive debug information can be gathered by setting:

core.config.isDebugVisible = true;

This information can then be written to an HTML element as follows:

const debug = document.getElementById("debug");
core.updateCallback = () => {
    debug.innerText = core.debugText.text;
};

Apps

The following apps use the MorphCharts library.

About

MorphCharts is a project from Microsoft Research. For questions and issues please contact morphcharts@microsoft.com.

Contact Us | Privacy & Cookies | Trademarks | Terms of Use | © 2022
Microsoft