D3js - GiovanniDw/frontend-applications GitHub Wiki
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
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.
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;
};
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
},{
...
}
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],
];
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.
select('g.pie')
selects the first g
element that has the classname .pie
.
const selection = select('g.pie');
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);
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()
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');
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'));