Week 5 Lab: Color scale exercises, Choropleth maps, Accessibility testing

CS-GY 6313 - Information Visualization

Ryan Kim

New York University

2026-10-02

Week 5 Lab Overview

User Interface Graphics Library Notebook
observablehq.com D3 Week 5 Lab Notebook

Today’s Lab Activities

Today we will be a coding-heavy lab where we will practice with color scales and geodata. The lab will be divided into these sessions:

  1. Intro to Scale Types & Color
  2. Coding Session 1: Scales and color scales (scatter plot)
  3. Geodata: Example
  4. Coding Session 2: Choropleth map + Color Scale
  5. Color Accessibility Session: Categorical palettes & colorblind Test
  6. Wrap up & Sharing

D3 Scales: Mapping Data to Pixels

D3.js scales are intended to map data domain → screen range

Common types:

Code Data Type Compatibility
d3.scaleLinear() Numeric data
d3.scaleLog() Skewed numeric data (e.g. income)
d3.scaleTime() Time/date axes

Linear Scale Example:

d3.scaleLinear()
  .domain([0,10])
  .range([0, 100])

// linear_scale_example(5) → 50
// linear_scale_example(3) → 30


Log Scale Example:

d3.scaleLog()
  .domain([1,100000])
  .range([0, 100])

// log_scale_example(3233) → 70.19211409223112


Time Scale Example:

d3.scaleTime()
  .domain([new Date(2025, 0, 1), new Date(2025, 11, 31)]) // Jan 1 to Dec 31, 2025
  .range([0, 100]) 

// time_scale_example(new Date(2025, 7, 12)) → 61.25228937728938

Coding Session #1: Scatter Plots, Scales, and Colors [~ 10mins]

Your Task:

In this coding session, you will be practicing with producing a scatter plot based on health data from different countries/regions. This session uses the gapminder data.

Starter Code:

An initialized chart with titles, but it’s missing the axes and data.

Goal(s):

  • Explore different quantitative scales (d3.scaleLinear(), d3.scaleLog())
  • Explore different coloration scales
  • Practice with domain() and range() when setting up plot axes.
  • Practice with data binding from raw datasets to D3 plots.

Color Scales: Sequential v.s. Categorical Color Scales

Sequential Color Scales

Sequential scales are used with numeric, continuous data to generate gradients:

d3.scaleSequential(d3.interpolateBlues)

d3.scaleSequential(['blue', 'yellow', 'red'])

This is generally good for:

  • Choropleth maps
  • Population density
  • Continuous metrics

Categorical Color Scales

Use combinations such as d3.scaleOrdinal() + d3.schemeCategory10 to map ordinal or nominal data to specific colors.

d3.scaleOrdinal(d3.schemeCategory10)

Other categorical schemes provided here.

Categorical scale are good for:

  • Regions (geodata)
  • Categories like continent, gender, etc.

D3’s In-Built Scales

Category D3 scale Typical use
Continuous d3.scaleLinear() Numeric → numeric/color/etc.
d3.scalePow() Power-transformed quantitative data
d3.scaleSqrt() Square-root scaling, especially symbol area
d3.scaleLog() Data spanning orders of magnitude
d3.scaleSymlog() Log-like scaling that can handle zero/negative values
d3.scaleRadial() Radial visual encodings
d3.scaleIdentity() Domain and range are identical
Temporal d3.scaleTime() Dates/times using local time
d3.scaleUtc() Dates/times using UTC
Sequential d3.scaleSequential() Continuous values → sequential interpolator
d3.scaleSequentialLog() Sequential + logarithmic transform
d3.scaleSequentialPow() Sequential + power transform
d3.scaleSequentialSqrt() Sequential + square-root transform
d3.scaleSequentialSymlog() Sequential + symmetric-log transform
d3.scaleSequentialQuantile() Quantile-based sequential encoding
Diverging d3.scaleDiverging() Continuous values around a meaningful midpoint
d3.scaleDivergingLog() Diverging + logarithmic transform
d3.scaleDivergingPow() Diverging + power transform
d3.scaleDivergingSqrt() Diverging + square-root transform
d3.scaleDivergingSymlog() Diverging + symmetric-log transform
Discrete / categorical d3.scaleOrdinal() Categories → arbitrary discrete values/colors
d3.scaleBand() Categories → evenly spaced bands
d3.scalePoint() Categories → evenly spaced points
Discretizing d3.scaleQuantize() Continuous domain → fixed number of discrete bins
d3.scaleQuantile() Continuous distribution → equal-count bins
d3.scaleThreshold() User-defined thresholds → discrete values

When in doubt…

Remember the core principles of domain, range, and scale:

  • Domain: The type and data values of the data you wish to manipulate.
  • Range: The pixels or colors you wish to map your data values into.
  • Scale: How should the mapping occur?

Everything in D3.js, from the X-axis to the Y-axis to the color scale, relies on this pattern.

Choropleth Maps

What is a Choropleth Map?

  • A map where regions are colored based on data.
  • Works best with sequential scales across geographical regions.

Example Src: D3

Coding Session #2: GeoMaps and Colors [~ 25mins]

Your Task:

In the example, we plotted a simple Mercator map. In this coding session, we will make it more interesting by binding the geodata to another dataset: population.

If you recall in Week 3 Exercise,, we generated the geomap of USA counties and their population data. To achieve this, we needed to link the population data to the geodata by some common feature. In that case, we joined the two datasets based on an id feature that was basically the zip codes of each USA county.

In this coding session, we will do something similar, but in D3 and using a world map instead of the USA counties map. We have provided the basic code for the Mercator map both in the example above and in this code session’s starter code. It’s your job to color the countries of the map to show their population sizes.

Starter Code:

The barebones code for the Mercator map.

Goals:

  • Create a JavaScript Map() to act as a lookup dictionary when mapping countries to populations.
  • Practice with color scales
  • Practice with rendering geodata.

Color & Accessibility

  • Approx. 1 in 12 people have color vision deficiency
  • Avoid red/green without contrast
  • Use tools to test (Coblis, Colorblind Testers)

Image src: “Color Advice for Data Visualization with D3.js” by Elijah Meeks

Coding Session #3: Color Accessibility Session [~ 5-10min]

In this section, we’ll be copying the scatter plot data used in Coding Session #1 but with some different twists. In the first coding session, you were tasked with using either d3.sequentialBlues for the health data or d3.schemeCategory10 for the categorical region data. However, many of these pre-determined schema can be hard to visually parse for people with ocular deficiencies such as color blindness.

To simulate the different variations of color blindness, you can go to this website. This is a very useful simulator that alters a sample image to let you see what certain ocular conditions look like.

Your Task:

For this coding session, you will copy-paste your code from Coding Session #1 and modify it to use a color scheme that aims to make the coloration accessible to people with Deuteranopia (green-blindness). One way we can do this is to use ColorBrewer palettes. For more information, look at this repository of different color palettes and search for “ColorBrewer”.

Once you have what you believe is an acceptable color visualization, hop over to https://bioapps.byu.edu/colorblind_image_tester and upload a PNG of your plot to receive a rating of whether it’s friendly or not to people with Deuteranopia.

End of Lab

In Today’s Lab:

  • D3.js scales
  • Sneak peek at Chloropleth maps

What Exercise #5 will cover:

  • More practice with D3.js scales
  • More practice with color scales and simple heatmaps
  • Practice with creating custom legends

Remember:

  • Exercise #5 will be posted tonight and is due on October 8th @ 11:59pm!
  • Where do I ask questions?
    • Office Hours!
    • Our course Discord!