Skip to content
Snippets Groups Projects
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;