Export Image

Fork of Parallel Coordinates with Brushing

Stephen HC Lin

Saturday, August 9, 2025: 0 viewsSunday, August 10, 2025: 0 viewsMonday, August 11, 2025: 0 viewsTuesday, August 12, 2025: 0 viewsWednesday, August 13, 2025: 0 viewsThursday, August 14, 2025: 0 viewsFriday, August 15, 2025: 0 viewsSaturday, August 16, 2025: 0 viewsSunday, August 17, 2025: 0 viewsMonday, August 18, 2025: 0 viewsTuesday, August 19, 2025: 0 viewsWednesday, August 20, 2025: 0 viewsThursday, August 21, 2025: 0 viewsFriday, August 22, 2025: 0 viewsSaturday, August 23, 2025: 0 viewsSunday, August 24, 2025: 0 viewsMonday, August 25, 2025: 0 viewsTuesday, August 26, 2025: 0 viewsWednesday, August 27, 2025: 0 viewsThursday, August 28, 2025: 0 viewsFriday, August 29, 2025: 0 viewsSaturday, August 30, 2025: 0 viewsSunday, August 31, 2025: 0 viewsMonday, September 1, 2025: 0 viewsTuesday, September 2, 2025: 0 viewsWednesday, September 3, 2025: 0 viewsThursday, September 4, 2025: 0 viewsFriday, September 5, 2025: 0 viewsSaturday, September 6, 2025: 0 viewsSunday, September 7, 2025: 0 viewsMonday, September 8, 2025: 0 viewsTuesday, September 9, 2025: 0 viewsWednesday, September 10, 2025: 0 viewsThursday, September 11, 2025: 0 viewsFriday, September 12, 2025: 0 viewsSaturday, September 13, 2025: 0 viewsSunday, September 14, 2025: 0 viewsMonday, September 15, 2025: 0 viewsTuesday, September 16, 2025: 0 viewsWednesday, September 17, 2025: 0 viewsThursday, September 18, 2025: 0 viewsFriday, September 19, 2025: 0 viewsSaturday, September 20, 2025: 0 viewsSunday, September 21, 2025: 0 viewsMonday, September 22, 2025: 0 viewsTuesday, September 23, 2025: 0 viewsWednesday, September 24, 2025: 0 viewsThursday, September 25, 2025: 0 viewsFriday, September 26, 2025: 0 viewsSaturday, September 27, 2025: 0 viewsSunday, September 28, 2025: 0 viewsMonday, September 29, 2025: 0 viewsTuesday, September 30, 2025: 0 viewsWednesday, October 1, 2025: 0 viewsThursday, October 2, 2025: 0 viewsFriday, October 3, 2025: 0 viewsSaturday, October 4, 2025: 0 viewsSunday, October 5, 2025: 0 viewsMonday, October 6, 2025: 0 viewsTuesday, October 7, 2025: 0 viewsWednesday, October 8, 2025: 0 viewsThursday, October 9, 2025: 0 viewsFriday, October 10, 2025: 0 viewsSaturday, October 11, 2025: 0 viewsSunday, October 12, 2025: 0 viewsMonday, October 13, 2025: 0 viewsTuesday, October 14, 2025: 0 viewsWednesday, October 15, 2025: 0 viewsThursday, October 16, 2025: 0 viewsFriday, October 17, 2025: 0 viewsSaturday, October 18, 2025: 0 viewsSunday, October 19, 2025: 0 viewsMonday, October 20, 2025: 0 viewsTuesday, October 21, 2025: 0 viewsWednesday, October 22, 2025: 0 viewsThursday, October 23, 2025: 0 viewsFriday, October 24, 2025: 0 viewsSaturday, October 25, 2025: 0 viewsSunday, October 26, 2025: 0 viewsMonday, October 27, 2025: 0 viewsTuesday, October 28, 2025: 0 viewsWednesday, October 29, 2025: 0 viewsThursday, October 30, 2025: 0 viewsFriday, October 31, 2025: 0 viewsSaturday, November 1, 2025: 0 viewsSunday, November 2, 2025: 0 viewsMonday, November 3, 2025: 0 viewsTuesday, November 4, 2025: 0 viewsWednesday, November 5, 2025: 0 views
10 views in last 90 days
Last edited Mar 22, 2024
Created on Mar 22, 2024

A parallel coordinates plot with brushing, multidimensional filtering, and responsiveness. Shows the Iris Dataset.

Also a test case for exporting code out of VizHub and into a Vite project! See also vite-export-template

Inspired by:

Creating Interactive Parallel Coordinates with D3

In this tutorial, we'll explore creating interactive parallel coordinates using D3.js. This visualization technique is perfect for multi-dimensional data exploration. We'll dive into key aspects like scales, line generators, and interactive brushing.

Setting Up the Environment

We start by importing necessary D3 modules and defining a helper function to adjust color hues:

import {
  select,
  scaleLinear,
  scalePoint,
  scaleOrdinal,
  schemeCategory10,
  extent,
  line,
  brushY,
  axisBottom,
  hcl,
} from 'd3';

const hueShift = (hueDelta) => (color) => {
  const newColor = hcl(color);
  newColor.h += hueDelta;
  return newColor.hex();
};

The hueShift function is a higher-order function that takes a hueDelta parameter and returns another function. This inner function takes a color parameter, applies a hue shift based on the hueDelta, and returns the resulting color in hexadecimal format. Here's a breakdown of its components:

  1. Higher-Order Function: hueShift is a higher-order function because it returns another function. The hueDelta parameter is used to specify how much to shift the hue of the color.

  2. Inner Function: The inner function takes a color parameter, which is expected to be a color string that can be understood by D3's hcl function (e.g., a hexadecimal color string).

  3. Color Conversion: The hcl function from D3 converts the input color string into an HCL (Hue, Chroma, Luminance) color object. HCL is a cylindrical color space that is similar to HSL and HSV.

  4. Hue Adjustment: The hue component (h) of the HCL color object is incremented by hueDelta. This effectively shifts the color's hue by the specified amount, wrapping around if necessary.

  5. Hexadecimal Conversion: Finally, the modified HCL color object is converted back to a hexadecimal color string using the .hex() method, and this string is returned as the result.

We use this later to add some flair to the default colors.

Defining Scales

We need to set up scales for our X and Y axes. For the X-axis, we use a scalePoint to evenly space our dimensions. For the Y-axes, we choose between scaleLinear and scalePoint based on the data type of each dimension:

const xScale = scalePoint()
  .domain(columns)
  .range([marginLeft, width - marginRight]);

const yScales = {};
for (const column of columns) {
  yScales[column] =
    columnTypes[column] === 'quantitative'
      ? scaleLinear()
          .domain(extent(data, (d) => d[column]))
          .range([height - marginBottom, marginTop])
      : scalePoint()
          .domain(data.map((d) => d[column]))
          .range([height - marginBottom, marginTop]);
}

Setting Up Color Scale

We use D3's scaleOrdinal to assign colors to our lines. The hueShift function adds a bit of flair to the default color scheme:

const colorScale = scaleOrdinal()
  .domain(data.map(colorValue))
  .range(schemeCategory10.map(hueShift(-74)));

Rendering Lines

We use D3's line generator to create paths for each data point. The X position is determined by the dimension, and the Y position is based on the data value. Here's a simplified version of the full logic that highlights how the lines are computed:

import { line } from 'd3';
const lineGenerator = line();
selection
  .selectAll('path')
  .data(filteredData)
  .join('path')
  .attr('d', (d) =>
    lineGenerator(
      columns.map((column) => [
        xScale(column),
        yScales[column](d[column]),
      ]),
    ),
  );

Note that we do not configure lineGenerator, so it uses the default X and Y accessors, which assume that each datum defines coordinates as [x, y] arrays. This is why we can map over the columns and return such arrays that define our desired coordinates. The X coordinate is computed by the X scale, whose domain is the list of columns. The Y coordinate is computed by the Y scale associated with the current column, which maps data values for that column to vertical positions.

Adding an X-axis

We add an X-axis to label our dimensions. The axisBottom function from D3 makes this easy:

selection
  .append('g')
  .attr('transform', `translate(0,${height})`)
  .call(axisBottom(xScale));

Main Function

Finally, we tie everything together in a main function that sets up the SVG element and calls our parallelCoordinates function:

export const main = (container, { state, setState }) => {
  // Logic omitted for computing dimensions updateBrushedInterval.

  // Set up the SVG.
  const svg = select(container)
    .selectAll('svg')
    .data([null])
    .join('svg')
    .attr('width', width)
    .attr('height', height)
    .style('background', '#090F10');

  // Invoke the parallel coordinates.
  svg.call(parallelCoordinates, {
    data,
    columns,
    columnTypes,
    colorValue,
    idValue,
    width,
    height,
    brushedIntervals,
    updateBrushedInterval,
  });
};

Here, we set up the SVG, and invoke our parallel coordinates function.

Conclusion

Parallel coordinates are a powerful tool for visualizing high-dimensional data. By leveraging D3.js, we can create interactive and customizable charts that offer deep insights into complex datasets. This tutorial provides a foundation for building more advanced visualizations with additional features and interactions.

Challenge

Fork this viz and modify it to show your own data!

MIT Licensed