Skip to content

Commit 08cb3ef

Browse files
ilenia-magonimoT01
andauthored
feat: Add Remaining Data Viz Projects (#318)
* add scatterplot graph * adding heat-map * adding choropleth map project * adding treemap-diagram project * update readme.md * fix where to add config * Update apps/choropleth-map/sample.env Co-authored-by: Tom <[email protected]>
1 parent aba3d0c commit 08cb3ef

29 files changed

+1551
-2
lines changed

CONTRIBUTE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ but I _strongly_ recommend at least reading it first. Just in case it has not be
4747

4848
- Make sure the new project is in the `port-map.json` file. Update also `package.json` and `package-lock.json`.
4949
- Make a PR to the `demo-projects-nginx-config` repo to configure the new app:
50-
- Add config in `/etc/nginx/sites-enabled/10-freecodecamp.rocks.conf` by copying config for one of the other projects and changing the names.
50+
- Add config in `/sites-enabled/10-freecodecamp.rocks.conf` by copying config for one of the other projects and changing the names.
5151
- Also add the title at the top.
5252
- Merge the PR
5353
- In the VM:

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,27 @@
2929
## Data Visualization
3030

3131
- Bar Chart
32+
3233
- [Project Description](https://www.freecodecamp.org/learn/data-visualization/data-visualization-projects/visualize-data-with-a-bar-chart)
3334
- [Example Project](https://bar-chart.freecodecamp.rocks/)
3435

36+
- Scatterplot Graph
37+
38+
- [Project Description](https://www.freecodecamp.org/learn/data-visualization/data-visualization-projects/visualize-data-with-a-scatterplot-graph)
39+
- [Example Project](https://scatterplot-graph.freecodecamp.rocks/)
40+
41+
- Heat Map
42+
43+
- [Project Description](https://www.freecodecamp.org/learn/data-visualization/data-visualization-projects/visualize-data-with-a-heat-map)
44+
- [Example Project](https://heat-map.freecodecamp.rocks/)
45+
46+
- Choropleth Map
47+
- [Project Description](https://www.freecodecamp.org/learn/data-visualization/data-visualization-projects/visualize-data-with-a-choropleth-map)
48+
- [Example Project](https://choropleth-map.freecodecamp.rocks/)
49+
- Treemap Diagram
50+
- [Project Description](https://www.freecodecamp.org/learn/data-visualization/data-visualization-projects/visualize-data-with-a-treemap-diagram)
51+
- [Example Project](https://treemap-diagram.freecodecamp.rocks/)
52+
3553
## APIs and Microservices
3654

3755
- Timestamp

apps/choropleth-map/index.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>FCC: D3 Choropleth Map</title>
5+
<link rel="stylesheet" href="styles.css" />
6+
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.4/d3.min.js"></script>
7+
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js"></script>
8+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/d3-scale-chromatic.min.js"></script>
9+
</head>
10+
<body>
11+
<div id="main">
12+
<h1 id="title">United States Educational Attainment</h1>
13+
<div id="description">
14+
Percentage of adults age 25 and older with a bachelor's degree or higher
15+
(2010-2014)
16+
</div>
17+
<svg width="960" height="600"></svg>
18+
<div id="source">
19+
Source:
20+
<a
21+
href="https://www.ers.usda.gov/data-products/county-level-data-sets/download-data.aspx"
22+
>USDA Economic Research Service</a
23+
>
24+
</div>
25+
</div>
26+
<script src="script.js"></script>
27+
</body>
28+
</html>

apps/choropleth-map/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "choropleth-map",
3+
"version": "0.0.1",
4+
"description": "Data Visualization project for freeCodeCamp",
5+
"main": "server.js",
6+
"scripts": {
7+
"start": "node server.js",
8+
"test": "wait-port -t 10000 3000"
9+
},
10+
"dependencies": {
11+
"dotenv": "^16.0.0",
12+
"express": "^4.17.3"
13+
}
14+
}

apps/choropleth-map/public/script.js

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/* global d3, topojson */
2+
/* eslint-disable max-len */
3+
4+
// eslint-disable-next-line no-unused-vars
5+
const projectName = 'choropleth';
6+
7+
// coded by @paycoguy & @ChristianPaul (github)
8+
9+
// Define body
10+
var body = d3.select('body');
11+
12+
var svg = d3.select('svg');
13+
14+
// Define the div for the tooltip
15+
var tooltip = body
16+
.append('div')
17+
.attr('class', 'tooltip')
18+
.attr('id', 'tooltip')
19+
.style('opacity', 0);
20+
21+
var path = d3.geoPath();
22+
23+
var x = d3.scaleLinear().domain([2.6, 75.1]).rangeRound([600, 860]);
24+
25+
var color = d3
26+
.scaleThreshold()
27+
.domain(d3.range(2.6, 75.1, (75.1 - 2.6) / 8))
28+
.range(d3.schemeGreens[9]);
29+
30+
var g = svg
31+
.append('g')
32+
.attr('class', 'key')
33+
.attr('id', 'legend')
34+
.attr('transform', 'translate(0,40)');
35+
36+
g.selectAll('rect')
37+
.data(
38+
color.range().map(function (d) {
39+
d = color.invertExtent(d);
40+
if (d[0] === null) {
41+
d[0] = x.domain()[0];
42+
}
43+
if (d[1] === null) {
44+
d[1] = x.domain()[1];
45+
}
46+
return d;
47+
})
48+
)
49+
.enter()
50+
.append('rect')
51+
.attr('height', 8)
52+
.attr('x', function (d) {
53+
return x(d[0]);
54+
})
55+
.attr('width', function (d) {
56+
return d[0] && d[1] ? x(d[1]) - x(d[0]) : x(null);
57+
})
58+
.attr('fill', function (d) {
59+
return color(d[0]);
60+
});
61+
62+
g.append('text')
63+
.attr('class', 'caption')
64+
.attr('x', x.range()[0])
65+
.attr('y', -6)
66+
.attr('fill', '#000')
67+
.attr('text-anchor', 'start')
68+
.attr('font-weight', 'bold');
69+
70+
g.call(
71+
d3
72+
.axisBottom(x)
73+
.tickSize(13)
74+
.tickFormat(function (x) {
75+
return Math.round(x) + '%';
76+
})
77+
.tickValues(color.domain())
78+
)
79+
.select('.domain')
80+
.remove();
81+
82+
const EDUCATION_FILE =
83+
'https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/for_user_education.json';
84+
const COUNTY_FILE =
85+
'https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/counties.json';
86+
87+
Promise.all([d3.json(COUNTY_FILE), d3.json(EDUCATION_FILE)])
88+
.then(data => ready(data[0], data[1]))
89+
.catch(err => console.log(err));
90+
91+
function ready(us, education) {
92+
svg
93+
.append('g')
94+
.attr('class', 'counties')
95+
.selectAll('path')
96+
.data(topojson.feature(us, us.objects.counties).features)
97+
.enter()
98+
.append('path')
99+
.attr('class', 'county')
100+
.attr('data-fips', function (d) {
101+
return d.id;
102+
})
103+
.attr('data-education', function (d) {
104+
var result = education.filter(function (obj) {
105+
return obj.fips === d.id;
106+
});
107+
if (result[0]) {
108+
return result[0].bachelorsOrHigher;
109+
}
110+
// could not find a matching fips id in the data
111+
console.log('could find data for: ', d.id);
112+
return 0;
113+
})
114+
.attr('fill', function (d) {
115+
var result = education.filter(function (obj) {
116+
return obj.fips === d.id;
117+
});
118+
if (result[0]) {
119+
return color(result[0].bachelorsOrHigher);
120+
}
121+
// could not find a matching fips id in the data
122+
return color(0);
123+
})
124+
.attr('d', path)
125+
.on('mouseover', function (event, d) {
126+
tooltip.style('opacity', 0.9);
127+
tooltip
128+
.html(function () {
129+
var result = education.filter(function (obj) {
130+
return obj.fips === d.id;
131+
});
132+
if (result[0]) {
133+
return (
134+
result[0]['area_name'] +
135+
', ' +
136+
result[0]['state'] +
137+
': ' +
138+
result[0].bachelorsOrHigher +
139+
'%'
140+
);
141+
}
142+
// could not find a matching fips id in the data
143+
return 0;
144+
})
145+
.attr('data-education', function () {
146+
var result = education.filter(function (obj) {
147+
return obj.fips === d.id;
148+
});
149+
if (result[0]) {
150+
return result[0].bachelorsOrHigher;
151+
}
152+
// could not find a matching fips id in the data
153+
return 0;
154+
})
155+
.style('left', event.pageX + 10 + 'px')
156+
.style('top', event.pageY - 28 + 'px');
157+
})
158+
.on('mouseout', function () {
159+
tooltip.style('opacity', 0);
160+
});
161+
162+
svg
163+
.append('path')
164+
.datum(
165+
topojson.mesh(us, us.objects.states, function (a, b) {
166+
return a !== b;
167+
})
168+
)
169+
.attr('class', 'states')
170+
.attr('d', path);
171+
}

apps/choropleth-map/public/styles.css

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
html,
2+
body {
3+
padding: 0;
4+
margin: 0;
5+
}
6+
7+
body {
8+
display: flex;
9+
justify-content: center;
10+
font-family: 'Arial';
11+
}
12+
13+
#main {
14+
width: 1000px;
15+
display: flex;
16+
padding-top: 1rem;
17+
flex-direction: column;
18+
align-items: center;
19+
}
20+
21+
.counties {
22+
fill: none;
23+
}
24+
25+
.states {
26+
fill: none;
27+
stroke: #fff;
28+
stroke-linejoin: round;
29+
}
30+
31+
div.tooltip {
32+
position: absolute;
33+
padding: 10px;
34+
font: 12px Arial;
35+
background: rgba(255, 255, 204, 0.9);
36+
box-shadow: 1px 1px 10px rgba(128, 128, 128, 0.6);
37+
border: 0px;
38+
border-radius: 2px;
39+
pointer-events: none;
40+
}
41+
42+
#title {
43+
font-size: 3.5rem;
44+
}
45+
46+
#description {
47+
text-align: center;
48+
}
49+
50+
#source {
51+
align-self: flex-end;
52+
margin-top: 1rem;
53+
}
54+
55+
a {
56+
text-decoration: none;
57+
}

apps/choropleth-map/sample.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PORT=""

apps/choropleth-map/server.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
require('dotenv').config();
2+
const express = require('express');
3+
const app = express();
4+
5+
app.use(express.static('public'));
6+
7+
app.get('', (req, res) => {
8+
res.sendFile(`${process.cwd()}/index.html`);
9+
});
10+
11+
const portNum = process.env.PORT || 3000;
12+
13+
app.listen(portNum, () => {
14+
console.log(`Listening on port ${portNum}`);
15+
});

apps/heat-map/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<link rel="stylesheet" href="styles.css" />
5+
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.4/d3.min.js"></script>
6+
<script src="https://unpkg.com/[email protected]/build/d3-v6-tip.js"></script>
7+
<title>FCC: D3 Heat Map</title>
8+
</head>
9+
<body>
10+
<script src="script.js"></script>
11+
</body>
12+
</html>

apps/heat-map/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "heat-map",
3+
"version": "0.0.1",
4+
"description": "Data Visualization project for freeCodeCamp",
5+
"main": "server.js",
6+
"scripts": {
7+
"start": "node server.js",
8+
"test": "wait-port -t 10000 3000"
9+
},
10+
"dependencies": {
11+
"dotenv": "^16.0.0",
12+
"express": "^4.17.3"
13+
}
14+
}

0 commit comments

Comments
 (0)