Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Data join example using Civil War data

Learn Data Join Pattern

Goal

Learn pattern to change data on the same chart. For example, change data from Union to Confederate.

Pattern: Data Doesn't Change

  1. selectAll( thing to draw such as circle )
  2. data - binds data to the thing to draw such as circle
  3. enter - new stuff to add
  4. append (thing to draw such as circle )

Pattern Additions: Change Data

  1. exit() is used to delete unused objects on screen
  2. update existing objects on screen with new data (such as circle color or size)

Pattern: Change Data

  1. select
  2. data
  3. exit - remove unused objects
  4. update existing objects
  5. enter
  6. append

Demo

https://bl.ocks.org/codetricity/raw/3f4958488fdf87b912988bfa77384661/

Setup

  1. Use the same data file on Civil War
  2. create new civilwar.js file or similar. Create new html file or edit existing

Read in Data

  1. read in data
    d3.csv('civil-war.csv').then((data) => {
  2. create blank arrays for union, confederate, border
  3. console.log the data so you can see what it looks like

Note that the data is an array of objects.

Use forEach to loop through array

Take out each object from the array.

The command below will loop through the array and return each element.

data.forEach((element) => {

Use console.log to print out each object.

Go through each key in object with for var in object

Each object has three keys.

Question: What are the keys?

This command will loop through each object.

for (var alliance in element) {

Pattern: for (variable in object)

console.log to print out each key for every object. console.log(alliance)

Use key to get value with object[key]

The name of the object is element.

The name of the key is alliance.

The value is element[alliance]

use console.log to print out each value.

Assign value to variable stateName

data.forEach((element) => {
   for (var alliance in element) {
     let stateName = element[alliance];

Populate arrays for union, confederate, border

if (stateName != "") {
  if (alliance == 'union') {
    union.push(stateName);
  } else if (alliance == 'confederate') {
    confederate.push(stateName);
  ... fill in rest

Create listAlliance function to process data

Pattern: 1. select, 2. join

function listAlliance(allianceData) {
  /**
   * Pattern:
   *  1. select
   *  2. data join
   *  3. exit and remove excess information on screen
   *  4. update information on screen
   *  5. enter
   *  6. append new items
   */
  const allianceText = svg.selectAll('text')  // 1. select
  .data(allianceData);  // 2. data join

Use console.log on allianceText to inspect the output.

Pattern: 3. exit

This removes items on screen that are not in the data array.

allianceText.exit()

Use console to see the results of alliance.exit()

Remove objects that are unused.

allianceText.exit().remove();   // 3. exit and remove excess information on screen

Pattern: 4. update

Update existing elements on screen with the new data.

allianceText.text(d => d); // 4. update information on screen

Pattern: 5. enter

Find data that needs to be added to screen.

allianceText.enter()  // 5. enter and return list of information that needs to be on screen

Pattern: 6. append

.append('text')     // 6. append
.text((d) => d)
.attr('x', '50')
.attr('y', (d, i) => i * 20 + 50);

Add radio buttons to html

<form>
  <input type="radio" value="union" name="alliance">
  <label>
    Union
  </label>
  <input type="radio" value="confederate" name="alliance" >
  <label>
    Confederate
  </label>
  <input type="radio" value="border" name="alliance" >
  <label>
    Border
  </label>
</form>

Look for Button change

const buttons = d3.selectAll('input');
buttons.on('change', function(d) {
  console.log('button changed to ' + this.value);

Process button change

const selection = this.value;
if (selection == 'union') {
  listAlliance(union);
... fill in the rest

Questions

  1. what does forEach do? Is it for an array or an object?
  2. what does `` for ... in ...`` do?
  3. There are 6 steps of the pattern to update data on the chart. Step 1 is select. Step 6 is append What are steps 2, 3, 4?
  4. What does enter() return?
  5. What does exit() return?
union confederate border
Maine Texas Maryland
New York Arkansas Delaware
New Hampshire Louisiana West Virginia
Vermont Tennessee Kentucky
Massachusetts Mississippi Missouri
Connecticut Alabama
Rhode Island Georgia
Pennsylvania Florida
New Jersey South Carolina
Ohio North Carolina
Indiana Virginia
Illinois
Kansas
Michigan
Wisconsin
Minnesota
Iowa
California
Nevada
Oregon
<head>
<meta charset='utf-8'>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js"></script>
<script src='main.js'></script>
<form>
<input type="radio" value="union" name="alliance">
<label>
Union
</label>
<input type="radio" value="confederate" name="alliance" >
<label>
Confederate
</label>
<input type="radio" value="border" name="alliance" >
<label>
Border
</label>
</form>
</body>
const svg = d3.select('body').append('svg')
.attr('width', '600')
.attr('height', '600');
d3.csv('civil-war.csv').then((data) => {
const union = [];
const confederate = [];
const border = [];
data.forEach((element) => {
for (var alliance in element) {
let stateName = element[alliance];
if (stateName != "") {
if (alliance == 'union') {
union.push(stateName);
}
else if (alliance == 'confederate') {
confederate.push(stateName);
} else if (alliance == 'border') {
border.push(stateName);
}
}
}
});
const buttons = d3.selectAll('input');
buttons.on('change', function(d) {
console.log('button changed to ' + this.value);
const selection = this.value;
if (selection == 'union') {
listAlliance(union);
} else if (selection == 'confederate') {
listAlliance(confederate);
} else if (selection == 'border') {
listAlliance(border);
}
});
});
function listAlliance(allianceData) {
/**
* Pattern:
* 1. data join
* 2. exit and remove excess information on screen
* 3. update information on screen
* 4. enter
* 5. append new items
*/
const allianceText = svg.selectAll('text')
.data(allianceData); // 1. data join
allianceText.exit().remove(); // 2. exit and remove excess information on screen
allianceText.text(d => d); // 3. update information on screen
allianceText.enter() // 4. enter and return list of information that needs to be on screen
.append('text') // 5. append
.text((d) => d)
.attr('x', '50')
.attr('y', (d, i) => i * 20 + 50);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.