In this section, we will explore how to use D3 scales to map data values to visual properties. Scales are a fundamental part of D3.js, allowing you to transform data values into positions, lengths, colors, and other visual properties.

Key Concepts

  1. Scales: Functions that map from an input domain to an output range.
  2. Domains: The set of input values.
  3. Ranges: The set of output values.
  4. Types of Scales: Linear, Ordinal, Time, Logarithmic, etc.

Types of Scales

Linear Scales

Linear scales are used for continuous quantitative data. They map a continuous input domain to a continuous output range.

// Create a linear scale
const linearScale = d3.scaleLinear()
    .domain([0, 100])  // Input domain
    .range([0, 500]);  // Output range

// Use the scale
console.log(linearScale(50));  // Output: 250
console.log(linearScale(75));  // Output: 375

Ordinal Scales

Ordinal scales are used for categorical data. They map a discrete domain to a discrete range.

// Create an ordinal scale
const ordinalScale = d3.scaleOrdinal()
    .domain(['A', 'B', 'C'])  // Input domain
    .range([10, 20, 30]);     // Output range

// Use the scale
console.log(ordinalScale('A'));  // Output: 10
console.log(ordinalScale('B'));  // Output: 20

Time Scales

Time scales are used for time-based data. They map a time domain to a continuous range.

// Create a time scale
const timeScale = d3.scaleTime()
    .domain([new Date(2020, 0, 1), new Date(2020, 11, 31)])  // Input domain
    .range([0, 100]);  // Output range

// Use the scale
console.log(timeScale(new Date(2020, 5, 1)));  // Output: 50

Logarithmic Scales

Logarithmic scales are used for data that spans several orders of magnitude. They map a continuous input domain to a continuous output range using a logarithmic function.

// Create a logarithmic scale
const logScale = d3.scaleLog()
    .domain([1, 1000])  // Input domain
    .range([0, 100]);   // Output range

// Use the scale
console.log(logScale(10));  // Output: 33.33
console.log(logScale(100)); // Output: 66.67

Practical Example: Creating a Bar Chart with Scales

Let's create a simple bar chart using linear scales to map data values to bar heights.

Step-by-Step Guide

  1. Set up the SVG container:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Bar Chart with D3 Scales</title>
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<body>
    <svg width="600" height="400"></svg>
    <script src="script.js"></script>
</body>
</html>
  1. Define the data and scales:
// script.js

const data = [10, 20, 30, 40, 50];

// Define the scales
const xScale = d3.scaleBand()
    .domain(data.map((d, i) => i))
    .range([0, 600])
    .padding(0.1);

const yScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([400, 0]);
  1. Create the bars:
// Select the SVG container
const svg = d3.select('svg');

// Create the bars
svg.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr('x', (d, i) => xScale(i))
    .attr('y', d => yScale(d))
    .attr('width', xScale.bandwidth())
    .attr('height', d => 400 - yScale(d))
    .attr('fill', 'steelblue');

Explanation

  • xScale: A band scale is used to create evenly spaced bars.
  • yScale: A linear scale is used to map data values to bar heights.
  • svg.selectAll('rect'): Selects all rect elements (none initially).
  • .data(data): Binds the data to the selection.
  • .enter(): Creates a new selection for the data points.
  • .append('rect'): Appends a rect element for each data point.
  • .attr('x', (d, i) => xScale(i)): Sets the x position of each bar.
  • .attr('y', d => yScale(d)): Sets the y position of each bar.
  • .attr('width', xScale.bandwidth()): Sets the width of each bar.
  • .attr('height', d => 400 - yScale(d)): Sets the height of each bar.
  • .attr('fill', 'steelblue'): Sets the fill color of each bar.

Exercises

Exercise 1: Create a Line Chart

  1. Data: [10, 20, 30, 40, 50]
  2. Task: Create a line chart using linear scales for both x and y axes.

Solution

// Define the data
const data = [10, 20, 30, 40, 50];

// Define the scales
const xScale = d3.scaleLinear()
    .domain([0, data.length - 1])
    .range([0, 600]);

const yScale = d3.scaleLinear()
    .domain([0, d3.max(data)])
    .range([400, 0]);

// Define the line generator
const line = d3.line()
    .x((d, i) => xScale(i))
    .y(d => yScale(d));

// Select the SVG container
const svg = d3.select('svg');

// Append the path
svg.append('path')
    .datum(data)
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('stroke-width', 2)
    .attr('d', line);

Exercise 2: Create a Scatter Plot

  1. Data: [{x: 10, y: 20}, {x: 20, y: 30}, {x: 30, y: 40}, {x: 40, y: 50}]
  2. Task: Create a scatter plot using linear scales for both x and y axes.

Solution

// Define the data
const data = [
    {x: 10, y: 20},
    {x: 20, y: 30},
    {x: 30, y: 40},
    {x: 40, y: 50}
];

// Define the scales
const xScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.x)])
    .range([0, 600]);

const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.y)])
    .range([400, 0]);

// Select the SVG container
const svg = d3.select('svg');

// Create the circles
svg.selectAll('circle')
    .data(data)
    .enter()
    .append('circle')
    .attr('cx', d => xScale(d.x))
    .attr('cy', d => yScale(d.y))
    .attr('r', 5)
    .attr('fill', 'steelblue');

Summary

In this section, we covered the basics of using D3 scales, including linear, ordinal, time, and logarithmic scales. We also created practical examples of a bar chart, line chart, and scatter plot using these scales. Understanding scales is crucial for mapping data values to visual properties effectively in D3.js. In the next section, we will delve deeper into creating various types of visualizations using these scales.

© Copyright 2024. All rights reserved