D3js - GiovanniDw/frontend-applications GitHub Wiki

How I've Used D3

D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG, and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.

Table of Contents

Grabbing the Data

The first thing that needs to be done when visualizing data is getting the data.

d3-fetch provides utility methods that will fetch data from a file and parses it into a Javascript Object.

d3-fetch is able to parse different file formats. including .json and .csv files.

I ran into some problems when fetching the data from the .csv, after some research I found out that I had to specify the delimiter.

To fetch the .csv data with ; as a delimiter i used the next function.

dsv(';', url, autoType, cleanParkingData).then(setData);

autoType is a function from d3 that transforms the type of values from the objects and makes them usable.

Manipulating the Data

cleanParkingData is a function I wrote to transform and edit some values for rendering to the DOM

const cleanParkingData = (d) => {
	cleanProvince(d);
	cleanUsage(d);
	d.id = +d.id;
	d.minimumHeightInMeters = +d.minimumHeightInMeters;
	d.latitude = +d.latitude;
	d.longitude = +d.longitude;
	d.capacity = +d.capacity;
	return d;
};

This functions replaces a value from d.province if there is one

const cleanProvince = (d) => {
	if (!d.province) return;
	d.province = d.province.replace('Fryslân', 'Friesland');
	return d;
};

This Functions replaces the d.usage values with values I want to render to the dom

const cleanUsage = (d) => {
	try {
		d.usage = d.usage
			.replace('park and ride', 'P+R Parkeerplaats')
			.replace('garage', 'Parkeergarage')
			.replace('terrain', 'Parkeerterrein');
		return d;
	} catch (error) {
		console.error(error);
	}

	return d;
};

Formating & Reducing

After manipulating and cleaning the data. I wanted the results to be formatted and reduced.

Function:

export const formatData = (data) => {
	return data.map((d) => {
		return {
			id: d.id,
			name: d.name,
			province: d.province,
			usage: d.usage,
			city: d.city,
			latitude: d.latitude,
			longitude: d.longitude,
			capacity: d.capacity,
			minHeign: d.minimumHeightInMeters,
		};
	});
};

The map function I wrote produces a new array with only the values I need.

Input:

{
	"id": 1,
	"name": "P+R Station Appingedam (Appingedam)",
	"staticDataUrl": "https://npropendata.rdw.nl//parkingdata/v2/static/fc749565-1fe9-42f0-920a-3b4e718d62f9",
	"dynamicDataUrl": "",
	"limitedAccess": "0",
	"uuid": "fc749565-1fe9-42f0-920a-3b4e718d62f9",
	"latitude": 53.325488634795,
	"longitude": 6.8620881539554,
	"city": "Appingedam",
	"country_code": "nl",
	"province": "Groningen",
	"region": "Noord-Nederland",
	"mark": "good",
	"usage": "P+R Parkeerplaats",
	"accessPoints": "1",
	"capacity": 22,
	"contactPersons": "1",
	"minimumHeightInMeters": 0,
	"openingTimes": "1",
	"tariffs": "1",
	"Operator": "Appingedam"
},
{
	...
}

Output:

{
	"id": 1,
	"name": "P+R Station Appingedam (Appingedam)",
	"province": "Groningen",
	"usage": "P+R Parkeerplaats",
	"city": "Appingedam",
	"latitude": 53.325488634795,
	"longitude": 6.8620881539554,
	"capacity": 22,
	"minHeign": 0
},{
	...
}

Transfomring Data.

To create a pie chart I had to manipulate and nest values. To do this I used the rollups function from d3. This function returns a nested array.

Function:

export const nestedData = (data) => {
	const nested = rollups(
		data,
		(v) => v.length,
		(d) => d.usage
	);
	return nested;
};

Input:

{
	"id": 1,
	"name": "P+R Station Appingedam (Appingedam)",
	"province": "Groningen",
	"usage": "P+R Parkeerplaats",
	"city": "Appingedam",
	"latitude": 53.325488634795,
	"longitude": 6.8620881539554,
	"capacity": 22,
	"minHeign": 0
},{
	...
}

Output:

[
	['P+R Parkeerplaats', 329],
	['Parkeergarage', 540],
	['Parkeerterrein', 114],
];

Manipulating The DOM

d3-selection

d3-selection has alternative methods to document.querySelector() and is called d3.select()

This method creates a d3 selection object with helper methods that can be used to manipulate the dom.

d3.select()

select('g.pie') selects the first g element that has the classname .pie.

const selection = select('g.pie');

d3.selectAll()

selectAll('g.arc') selects all g.arc elements that will be rendered to the dom and .data(pieData) binds data to these elements.

const selectionWithData = selection.selectAll('g.arc').data(pieData);

d3.exit() & d3.remove()

These d3 methods will remove elements from the DOM if the associated data to that element is changed or removed.

selectionWithData.exit().remove();

selection.enter() & selection.append()

selection.enter() gets enter selection of data with missing elements. selection.append('g') creates dom elements for each data point without a DOM element

const selectionWidthUpdate = selectionWithData
	.enter()
	.append('g')
	.attr('class', 'arc');

selection.merge();

returns a new selection merging this selectionWidthUpdate with the specified other selection.

In this case
selectionWidthUpdate() is merged with selectionWithData.select('path.arc')

const path = selectionWidthUpdate
	.append('path')
	.merge(selectionWithData.select('path.arc'));
⚠️ **GitHub.com Fallback** ⚠️