Commit 77540f14 authored by Aimery Methena's avatar Aimery Methena
Browse files

Added our visualizations, just need to format so their placement is better

parent 1de0f168
Pipeline #528678833 passed with stage
in 1 minute and 59 seconds
This diff is collapsed.
......@@ -24,6 +24,7 @@
"react-twitter-embed": "^4.0.4",
"react-twitter-widgets": "^1.10.0",
"reactstrap": "^9.0.1",
"recharts": "^2.1.9",
"web-vitals": "^2.1.4"
},
"scripts": {
......
......@@ -16,6 +16,7 @@ import NavigationBar from './components/Navbar';
import PoliticianPage from './pages/Politicians/politicianPage';
import ElectionPage from './pages/PastElections/electionPage';
import DistrictPage from './pages/Districts/districtPage';
import OurVisualizations from './pages/Visualizations/Ours/ourVisualizations';
function App() {
......@@ -30,6 +31,8 @@ function App() {
<Route exact path='/districts' element={<Districts />} />
<Route exact path='/elections' element={<Elections />} />
<Route exact path='/search' element={<Search />} />
<Route exact path='/ourvisualizations' element={<OurVisualizations />} />
<Route exact path='/othervisualizations' />
<Route path='/politicians/:id' element={<PoliticianPage />} />
<Route path='/districts/:id' element={<DistrictPage />} />
<Route path='/elections/:id' element={<ElectionPage />} />
......
......@@ -17,6 +17,8 @@ const NavigationBar = () => {
<Nav.Link href="/politicians">Politicians</Nav.Link>
<Nav.Link href="/districts">Districts</Nav.Link>
<Nav.Link href="/elections">Elections</Nav.Link>
<Nav.Link href="/ourvisualizations">Visualizations</Nav.Link>
<Nav.Link href="/othervisualizations">Provider Visualizations</Nav.Link>
<Nav.Link href="/search">Search</Nav.Link>
</Navbar.Collapse>
</Container>
......
export const POLITICIAN_API = 'https://api.electrends.me/politicians';
export const ELECTION_API = 'https://api.electrends.me/elections';
export const DISTRICT_API = 'https://api.electrends.me/districts';
export const PIE_COLORS = [
"#EE00FF",
"#0088FE",
"#00C49F",
"#FFBB28",
"#FF8042",
]
export const POLITICIAN_FILTERS = [
{
name: "gov_level",
......
import React from "react";
import { Bar, BarChart, CartesianGrid, Legend, Tooltip, XAxis, YAxis } from "recharts";
function OurBarChart(props) {
console.log("bardata", props?.data);
return(
<BarChart width={730} height={250} data={props?.data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis unit={"%"}/>
<Tooltip />
<Legend />
<Bar dataKey="Highschool" fill="#8884d8" />
<Bar dataKey="College" fill="#82ca9d" />
</BarChart>
);
}
export default OurBarChart;
\ No newline at end of file
import React from "react";
import { PieChart, Pie, Cell } from "recharts";
import { PIE_COLORS } from "../../../constants";
import { Col, Row } from 'reactstrap';
function OurPieChart(props) {
console.log("piedata", props?.data);
let renderLabel = function(entry) {
return entry.name;
}
return(
<Row>
<Col>
<PieChart width={400} height={400}>
<Pie data={props?.data[0]} dataKey="value" nameKey="name" cx="50%" cy="50%" outerRadius={80} label={renderLabel}>
{props?.data[0]?.map((entry, index) => (
<Cell key={`cell-${index}`} fill={PIE_COLORS[index]}/>
))}</Pie>
</PieChart>
</Col>
<Col>
<PieChart width={400} height={400}>
<Pie data={props?.data[1]} dataKey="value" nameKey="name" cx="50%" cy="50%" outerRadius={80} label={renderLabel}>
{props?.data[1]?.map((entry, index) => (
<Cell key={`cell-${index}`} fill={PIE_COLORS[index]}/>
))}</Pie>
</PieChart>
</Col>
</Row>
);
}
export default OurPieChart;
\ No newline at end of file
import React from "react";
import { CartesianGrid, Legend, Scatter, ScatterChart, Tooltip, XAxis, YAxis } from "recharts";
function OurScatterChart(props) {
console.log("scatterdata", props?.data);
const dateFormat = (msec) => {
let date = new Date(msec);
let month = date.getUTCMonth() + 1; //months from 1-12
let day = date.getUTCDate();
let year = date.getUTCFullYear();
return month + "/" + day + "/" + year;
}
return(
<ScatterChart width={730} height={250}
margin={{ top: 20, right: 20, bottom: 10, left: 10 }}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="x" type="number" name="District Population" domain={['dataMin - 10000', 'dataMax + 10000']} label={{ value: 'District Population', position: 'insideBottomRight', offset: -10 }} />
<YAxis dataKey="y" name="Turnout" unit={"%"} label={{ value: 'Turnout', angle: -90, position: 'insideLeft' }} />
<Tooltip cursor={{ strokeDasharray: '3 3' }} />
<Legend />
<Scatter name="Democrat" data={props.data[0]} fill="#0015bc" />
<Scatter name="Republican" data={props.data[1]} fill="#e9141d" />
<Scatter name="Libertarian" data={props.data[2]} fill="#fed105" />
<Scatter name="Other" data={props.data[3]} fill="#00ff00" />
</ScatterChart>
);
}
export default OurScatterChart;
\ No newline at end of file
import axios from "axios";
import React, { useEffect, useState } from "react";
import { POLITICIAN_API, DISTRICT_API, ELECTION_API } from "../../../constants";
import OurBarChart from "./ourBarChart";
import OurPieChart from "./ourPieChart";
import OurScatterChart from "./ourScatterChart";
function OurVisualizations() {
const income_threshold = 50000;
const [loading, setLoading] = useState(false);
const [scatterLoading, setScatterLoading] = useState(false);
const [pieData, setPieData] = useState([]);
const [barData, setBarData] = useState([]);
const [scatterData, setScatterData] = useState([]);
useEffect(() => {
setLoading(true);
axios.get(DISTRICT_API, {
params: {
per_page: 1000,
type: "House of Representatives"
}})
.then(function (response) {
console.log(response);
setPieData(computePieData(response.data.districts));
setBarData(computeBarData(response.data.districts));
})
.catch(function (error) {
console.error(error);
})
.then( function () {
setLoading(false);
})
}, []);
useEffect(() => {
setScatterLoading(true);
axios.get(ELECTION_API, {
params: {
per_page: 1000
}})
.then(function (response) {
console.log(response);
setScatterData(computeScatterData(response.data.elections));
})
.catch(function (error) {
console.error(error);
})
.then( function () {
setScatterLoading(false);
})
}, []);
const computePieData = (districtData) => {
var low = [ {"name": "Hispanic", "value": 0},
{"name": "Asian", "value": 0},
{"name": "Black", "value": 0},
{"name": "Native or Pacific Islander", "value": 0},
{"name": "White", "value": 0}];
var all = [ {"name": "Hispanic", "value": 0},
{"name": "Asian", "value": 0},
{"name": "Black", "value": 0},
{"name": "Native or Pacific Islander", "value": 0},
{"name": "White", "value": 0}];
let low_cnt = 0;
let all_cnt = 0;
districtData.forEach(district => {
all[0].value += district.ethnicity_hispanic;
all[1].value += district.race_asian;
all[2].value += district.race_black;
all[3].value += district.race_native;
all[3].value += district.race_pacific_island;
all[4].value += district.race_white;
all_cnt++;
if(district.median_income <= income_threshold) {
low[0].value += district.ethnicity_hispanic;
low[1].value += district.race_asian;
low[2].value += district.race_black;
low[3].value += district.race_native;
low[3].value += district.race_pacific_island;
low[4].value += district.race_white;
low_cnt++;
}
});
low.forEach(group => {
group.value = group.value / low_cnt;
});
all.forEach(group => {
group.value = group.value / all_cnt;
});
return [low, all];
}
const computeBarData = (districtData) => {
var data = [{"name": "White", "Highschool": 0, "College": 0},
{"name": "Black", "Highschool": 0, "College": 0},
{"name": "Hispanic", "Highschool": 0, "College": 0},
{"name": "Native or Pacific Islander", "Highschool": 0, "College": 0},
{"name": "Asian", "Highschool": 0, "College": 0}];
const cnts = [0, 0, 0, 0, 0];
districtData.forEach(district => {
if(district.majority_race === "White"){
data[0].Highschool += district.hs_grad;
data[0].College += district.college_grad;
++cnts[0];
} else if(district.majority_race === "Black"){
data[1].Highschool += district.hs_grad;
data[1].College += district.college_grad;
++cnts[1];
} else if(district.majority_race === "Hispanic"){
data[2].Highschool += district.hs_grad;
data[2].College += district.college_grad;
++cnts[2];
} else if(district.majority_race === "Asian"){
data[4].Highschool += district.hs_grad;
data[4].College += district.college_grad;
++cnts[4];
} else {
data[3].Highschool += district.hs_grad;
data[3].College += district.college_grad;
++cnts[3];
}
});
data.forEach((category, index) => {
category.College /= cnts[index];
category.Highschool /= cnts[index];
});
return data;
}
const computeScatterData = (electionData) => {
const dems = [];
const repubs = [];
const liberts = [];
const other = [];
electionData.forEach(election => {
if(election.num_votes > 1 && election.num_votes < 1000000) {
if(election.winning_party === "Democratic") {
dems.push({ "x": election.district.population,/*Date.parse(election.general_date),*/
"y": ((election.num_votes / election.district.population) * 100).toFixed(2)})
} else if(election.winning_party === "Republican") {
repubs.push({ "x": election.district.population,/*Date.parse(election.general_date),*/
"y": ((election.num_votes / election.district.population) * 100).toFixed(2)})
} else if(election.winning_party === "Libertarian") {
liberts.push({ "x": election.district.population,/*Date.parse(election.general_date),*/
"y": ((election.num_votes / election.district.population) * 100).toFixed(2)})
} else if(election.winning_party !== "TBD"){
other.push({ "x": election.district.population,/*Date.parse(election.general_date),*/
"y": ((election.num_votes / election.district.population) * 100).toFixed(2)})
}
}
});
dems.sort((a, b) => (a.x > b.x) ? 1 : -1);
repubs.sort((a, b) => (a.x > b.x) ? 1 : -1);
liberts.sort((a, b) => (a.x > b.x) ? 1 : -1);
other.sort((a, b) => (a.x > b.x) ? 1 : -1);
return [dems, repubs, liberts, other];
}
if(loading || scatterLoading) {
return(
<div>
</div>
)
}
return(
<div>
<OurPieChart data={pieData}/>
<OurBarChart data={barData}/>
<OurScatterChart data={scatterData}/>
</div>
);
};
export default OurVisualizations;
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment