-
Bjarke Madsen authoredBjarke Madsen authored
DataAnalysis.tsx 9.26 KiB
import React, { ReactElement, useEffect, useState } from 'react';
import { Accordion, Col, Container, ListGroup, Row } from "react-bootstrap";
import LineGraph from "../components/graphing/LineGraph";
import { BudgetMatrix, DataEntrySection, Budget } from "../Schema";
export const options = {
// indexAxis: 'y' as const,
responsive: true,
plugins: {
legend: {
position: 'top' as const,
},
title: {
display: true,
text: 'Loading...',
},
},
};
function DataAnalysis(): ReactElement {
function api<T>(url: string, options: RequestInit | undefined = undefined): Promise<T> {
return fetch(url, options)
.then((response) => {
if (!response.ok) {
return response.text().then((message) => {
console.error(`Failed to load datax: ${message}`, response.status);
throw new Error("The data could not be loaded, check the logs for details.");
});
}
return response.json() as Promise<T>;
})
}
const [budgetMatrixResponse, setBudgetMatrixResponse] = useState<BudgetMatrix>();
const [budgetResponse, setBudget] = useState<Budget[]>();
const [dataEntrySection, setDataEntrySection] = useState<DataEntrySection>();
const [selectedDataEntry, setSelectedDataEntry] = useState<number>(0);
useEffect(() => {
// hardcode selected section for now
const dataEntrySectionResponse: DataEntrySection = {
description: "Org",
items: [
{
id: 0,
title: "NREN Budgets per year, in Millions EUR",
url: "/api/data-entries/item/2"
}
// {
// id:3,
// title:"NREN Budgets per NREN, in Millions EUR",
// url:"/api/data-entries/item/3"
// }
],
name: "Organisation"
}
setDataEntrySection(dataEntrySectionResponse);
setSelectedDataEntry(dataEntrySectionResponse.items[0].id);
}, [])
useEffect(() => {
const loadData = async () => {
console.log("budgetResponse "+ budgetResponse)
if (budgetResponse == undefined) {
api<Budget[]>('/api/budget/', {})
.then((budget: Budget[]) => {
console.log('budget.data :', budget)
console.log('budget :', budget)
const entry = dataEntrySection?.items.find(i => i.id == selectedDataEntry)
console.log(selectedDataEntry, dataEntrySection, entry)
if (entry)
options.plugins.title.text = entry.title;
setBudget(budget)
console.log("budgetResponse after api "+ budgetResponse)
convertToBudgetPerYearDataResponse(budget)
})
.catch(error => {
console.log(`Error fetching from API: ${error}`);
})
} else {
convertToBudgetPerYearDataResponse(budgetResponse)
}
}
loadData()
}, [dataEntrySection, selectedDataEntry]);
const empty_bar_response = {
data: {
datasets: [
{
backgroundColor: '',
data: [],
label: ''
}],
labels: []
},
description: "",
id: "",
settings: {},
title: ""
}
const empty_budget_response = [{
BUDGET: "",
BUDGET_YEAR: 0,
NREN: "",
id: 0
}]
const convertToBudgetPerYearDataResponse = (budgetResponse: Budget[]) => {
const barResponse = budgetResponse != undefined ? budgetResponse : empty_budget_response;
console.log("barResponse "+barResponse);
console.log(barResponse.map((item) => item.BUDGET_YEAR));
const labelsYear = [...new Set(barResponse.map((item) => item.BUDGET_YEAR))];
const labelsNREN = [...new Set(barResponse.map((item) => item.NREN))];
function getRandomColor() {
const red = Math.floor(Math.random() * 256).toString(16).padStart(2, '0'); // generates a value between 00 and ff
const green = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
const blue = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
return `#${red}${green}${blue}`;
}
function dataForNRENForYear(year: number, nren: string) {
const budget = barResponse.find(function (entry, index) {
if (entry.BUDGET_YEAR == year && entry.NREN == nren) {
return Number(entry.BUDGET);
}
})
return budget !== undefined ? Number(budget.BUDGET) : null;
}
const datasetPerYear = labelsYear.map(function (year) {
const randomColor = getRandomColor();
return {
backgroundColor: randomColor,
borderColor: randomColor,
data: labelsNREN.map(nren => dataForNRENForYear(year, nren)),
label: year.toString()
}
})
const datasetPerNREN = labelsNREN.map(function (nren) {
const randomColor = getRandomColor();
return {
backgroundColor: randomColor,
borderColor: randomColor,
data: labelsYear.map(year => dataForNRENForYear(year, nren)),
label: nren
}
})
if (selectedDataEntry == 0) {
const dataResponse: BudgetMatrix = {
data: {
datasets: datasetPerNREN,
labels: labelsYear.map(l => l.toString())
},
description: "The numbers are based on 30 NRENs that " +
"reported their budgets continuously throughout this" +
" period. This means that some larger NRENs are not" +
" included and therefore the actual total budgets will" +
" have been higher. (For comparison, the total budget" +
" according to the 2021 survey results based on the data" +
" for all responding NRENs that year is €555 M). The" +
" percentage change is based on the previous year's" +
" budget.",
id: "3",
settings: {},
title: 'NREN Budgets per NREN, in Millions EUR'
}
setBudgetMatrixResponse(dataResponse);
}
else {
const dataResponse: BudgetMatrix = {
data: {
datasets: datasetPerYear,
labels: labelsNREN.map(l => l.toString())
},
description:
"The numbers are based on 30 NRENs that reported their " +
"budgets continuously throughout this period. This " +
"means that some larger NRENs are not included and " +
"therefore the actual total budgets will have been " +
"higher. (For comparison, the total budget according to" +
" the 2021 survey results based on the data for all" +
" responding NRENs that year is €555 M). The percentage" +
" change is based on the previous year’s budget.",
id: "2",
settings: {},
title: 'NREN Budgets per year, in Millions EUR'
}
setBudgetMatrixResponse(dataResponse);
}
}
const budgetAPIResponse: BudgetMatrix = budgetMatrixResponse !== undefined
? budgetMatrixResponse : empty_bar_response;
return (
<div>
<h1>Data Analysis</h1>
<Container>
<Row>
<Col>
<Row>
<LineGraph data={budgetAPIResponse.data} />
</Row>
<Row>{budgetMatrixResponse?.description}</Row>
</Col>
<Col xs={3}>
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>Items</Accordion.Header>
<Accordion.Body>
<ListGroup>
{
dataEntrySection?.items.map((item) => (
<ListGroup.Item key={item.id} action active={item.id == selectedDataEntry} onClick={() => setSelectedDataEntry(item.id)}>{item.title}</ListGroup.Item>
))
}
</ListGroup>
</Accordion.Body>
</Accordion.Item>
</Accordion>
</Col>
</Row>
</Container>
</div>
);
}
export default DataAnalysis;