<?xml version="1.0" encoding="UTF-16"?>
<!-- This XML file has been created by WebEJS 1.0. Visit http://t.um.es/webejs -->
<!-- Please, open it with WebEJS or save the file to your hard disk on your EJS' user directory and open it with Desktop Ejs 6.01 or later. -->
<Osejs version="7.0" password="">
<Osejs.Information>
<Title><![CDATA[Urban_Population]]></Title>
<Copyright><![CDATA[]]></Copyright>
<Keywords><![CDATA[]]></Keywords>
<Password><![CDATA[unused]]></Password>
<Level><![CDATA[]]></Level>
<Language><![CDATA[]]></Language>
<Abstract><![CDATA[]]></Abstract>
<FixedNavigationBar>false</FixedNavigationBar>
<RunAlways>true</RunAlways>
<UseInterpreter>true</UseInterpreter>
<UseDeltaForODE>false</UseDeltaForODE>
<PreviewFullModel>false</PreviewFullModel>
<ModelTab></ModelTab>
<ModelTabTitle><![CDATA[]]></ModelTabTitle>
<ModelName><![CDATA[]]></ModelName>
<CSSFile></CSSFile>
<HTMLHead><![CDATA[
<script>
    function loadScript(localPath, fallbackUrl) {
        let script = document.createElement('script');
        script.src = localPath;
        script.onload = function () {
            console.log(`Loaded: ${localPath}`);
        };
        script.onerror = function () {
            console.warn(`Local script ${localPath} failed to load. Falling back to ${fallbackUrl}`);
            let fallbackScript = document.createElement('script');
            fallbackScript.src = fallbackUrl;
            fallbackScript.crossOrigin = "anonymous";
            fallbackScript.referrerPolicy = "no-referrer";
            document.head.appendChild(fallbackScript);
        };
        document.head.appendChild(script);
    }

    // Load Plotly
    loadScript('./lib/plotly-2.35.2.min.js', 'https://cdn.plot.ly/plotly-2.35.2.min.js');

    // Load Math.js
    loadScript('./lib/math.js', 'https://cdnjs.cloudflare.com/ajax/libs/mathjs/13.1.1/math.js');

    // Load Simple Statistics
    loadScript('./lib/simple-statistics.min.js', 'https://cdn.jsdelivr.net/npm/simple-statistics@7.8.5/dist/simple-statistics.min.js');

    // Load Regression
    loadScript('./lib/regression.min.js', 'https://cdn.jsdelivr.net/npm/regression@2.0.1/dist/regression.min.js');
</script>
]]></HTMLHead>
<SaveInXMLFormat>true</SaveInXMLFormat>
<IncludeSource>true</IncludeSource>
<IncludeLibrary>true</IncludeLibrary>
<UglifyJS>false</UglifyJS>
<Logo>./logogeog.png</Logo>
<Author><![CDATA[kangrui;lookang;enqi]]></Author>
<AuthorLogo>;;</AuthorLogo>
<DetectedFiles><![CDATA[./logogeog.png]]></DetectedFiles>
<AuxiliaryFiles><![CDATA[;./lib/;./lib/plotly-2.35.2.min.js;./annual-co2-emissions-per-country.csv;./lib/plotly-2.35.2.min.js]]></AuxiliaryFiles>
</Osejs.Information>
<Osejs.Description>
</Osejs.Description>
<Osejs.Model>
<Osejs.Model.FramesPerSecond>20</Osejs.Model.FramesPerSecond>
<Osejs.Model.StepsPerDisplay>1</Osejs.Model.StepsPerDisplay>
<Osejs.Model.RealTimeVariable></Osejs.Model.RealTimeVariable>
<Osejs.Model.Autostart>true</Osejs.Model.Autostart>
<Osejs.Model.Variables>
<Osejs.Model.Variables.Page>
<Type>undefined</Type>
<Name>Var Table 1</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<PageComment><![CDATA[]]></PageComment>
<Variable>
<Name><![CDATA[annualCO2Emissions]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[urbanPopulation]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[gdpPerCapita]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[infantMortalityRate]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[lifeExpectancy]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[type]]></Name>
<Value><![CDATA[{mode: "markers", type: "scatter"}]]></Value>
<Type><![CDATA[String]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[currentX]]></Name>
<Value><![CDATA["year"]]></Value>
<Type><![CDATA[String]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[currentY]]></Name>
<Value><![CDATA["urban population"]]></Value>
<Type><![CDATA[String]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[countries]]></Name>
<Value><![CDATA[[     "Brunei",     "Cambodia",     "East Timor",     "Indonesia",     "Laos",     "Malaysia",     "Myanmar",     "Philippines",     "Singapore",     "Thailand",     "Vietnam",     "World" ];]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[selectedCountries]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[plot]]></Name>
<Value><![CDATA["lines"]]></Value>
<Type><![CDATA[String]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[dataSources]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[]]></Name>
<Value><![CDATA[]]></Value>
<Type><![CDATA[double]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
</Content>
</Osejs.Model.Variables.Page>
<Osejs.Model.Variables.Page>
<Type>VARIABLE_EDITOR</Type>
<Name>lookang</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<PageComment><![CDATA[]]></PageComment>
<Variable>
<Name><![CDATA[colorPalette]]></Name>
<Value><![CDATA[[]]]></Value>
<Type><![CDATA[String]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[countriesLookang]]></Name>
<Value><![CDATA[{}]]></Value>
<Type><![CDATA[Object]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[selectAll]]></Name>
<Value><![CDATA[false]]></Value>
<Type><![CDATA[boolean]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[]]></Name>
<Value><![CDATA[]]></Value>
<Type><![CDATA[double]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
</Content>
</Osejs.Model.Variables.Page>
</Osejs.Model.Variables>
<Osejs.Model.Initialization>
<Osejs.Model.Initialization.Page>
<Type>CODE_EDITOR</Type>
<Name>initCountries</Name>
<Active>false</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
const countriesDiv = document.querySelector('.countries');
const selectAllDiv = document.querySelector('.select-all');

const selectAllCheckbox = document.createElement('input');
selectAllCheckbox.type = 'checkbox';
selectAllCheckbox.id = 'select-all';
selectAllCheckbox.value = 'Select All';

const selectAllLabel = document.createElement('label');
selectAllLabel.htmlFor = 'select-all';
selectAllLabel.textContent = 'Select All';

selectAllDiv.appendChild(selectAllCheckbox);
selectAllDiv.appendChild(selectAllLabel);

countries.forEach((country, index) => {
    const checkboxContainer = document.createElement('div');
    
    const checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.id = country;
    checkbox.value = country;

    const label = document.createElement('label');
    label.htmlFor = country;
    label.textContent = country;

    if (index < 0) {
        checkbox.checked = true;
        selectedCountries.push(country);
    }

    checkboxContainer.appendChild(checkbox);
    checkboxContainer.appendChild(label);
    countriesDiv.appendChild(checkboxContainer);

    checkbox.addEventListener('change', () => {
        if (checkbox.checked) {
            selectedCountries.push(checkbox.value);
        } else {
            const index = selectedCountries.indexOf(checkbox.value);
            if (index > -1) {
                selectedCountries.splice(index, 1);
            }
        }
        updateSelectAllCheckboxState();
        generateGraph(currentX, currentY);
    });
});

selectAllCheckbox.addEventListener('change', () => {
    const allCheckboxes = countriesDiv.querySelectorAll('input[type="checkbox"]:not(#select-all)');
    allCheckboxes.forEach((checkbox) => {
        checkbox.checked = selectAllCheckbox.checked;
        if (selectAllCheckbox.checked) {
            if (!selectedCountries.includes(checkbox.value)) {
                selectedCountries.push(checkbox.value);
            }
        } else {
            const index = selectedCountries.indexOf(checkbox.value);
            if (index > -1) {
                selectedCountries.splice(index, 1);
            }
        }
    });
    generateGraph(currentX, currentY);
});

function updateSelectAllCheckboxState() {
    const allCheckboxes = countriesDiv.querySelectorAll('input[type="checkbox"]:not(#select-all)');
    selectAllCheckbox.checked = Array.from(allCheckboxes).every(checkbox => checkbox.checked);
}

]]></Code>
</Content>
</Osejs.Model.Initialization.Page>
<Osejs.Model.Initialization.Page>
<Type>CODE_EDITOR</Type>
<Name>initVariables</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
countriesLookang = {
  "Brunei": false,
  "Cambodia": false,
  "East Timor": false,
  "Indonesia": false,
  "Laos": false,
  "Malaysia": false,
  "Myanmar": false,
  "Philippines": false,
  "Singapore": false,
  "Thailand": false,
  "Vietnam": false,
  "World": false
}
]]></Code>
</Content>
</Osejs.Model.Initialization.Page>
<Osejs.Model.Initialization.Page>
<Type>CODE_EDITOR</Type>
<Name>dataSources</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
const dataSources = [
    {
        text: 'Global Carbon Budget (2023) – with major processing by Our World in Data. “Annual CO₂ emissions – GCB” [dataset]. Global Carbon Project, “Global Carbon Budget” [original data]. Retrieved September 20, 2024 from ',
        link: 'https://ourworldindata.org/grapher/annual-co2-emissions-per-country',
    },
    {
        text: 'Multiple sources compiled by World Bank (2024) – processed by Our World in Data. “Share of the population living in urban areas” [dataset]. UN Population Division (via World Bank), “World Development Indicators” [original data]. Retrieved September 20, 2024 from ',
        link: 'https://ourworldindata.org/grapher/share-of-population-urban',
    },
    {
        text: 'UN WPP (2022); HMD (2023); Zijdeman et al. (2015); Riley (2005) – with minor processing by Our World in Data. “Life expectancy at birth – Various sources – period tables” [dataset]. Human Mortality Database, “Human Mortality Database”; United Nations, “World Population Prospects 2022”; United Nations, “World Population Prospects”; Zijdeman et al., “Life Expectancy at birth 2”; James C. Riley, “Estimates of Regional and Global Life Expectancy, 1800-2001” [original data]. Retrieved September 20, 2024 from ',
        link: 'https://ourworldindata.org/grapher/life-expectancy',
    },
    {
        text: 'United Nations, Economic and Social Commission for Asia and the Pacific (n.d.). Country Profiles: Demographic changes in Asia and the Pacific. Retrieved September 20, 2024 from ',
        link: 'https://www.population-trends-asiapacific.org/data',
    },
    {
        text: 'United Nations, Department of Economic and Social Affairs, Population Division (2024). World Population Prospects 2024, Online Edition. Retrieved September 20, 2024 from ',
        link: 'https://population.un.org/wpp/Download/Standard/MostUsed/',
    },
    {
        text: 'World Bank Group. (2024). GDP per capita, PPP (current international $). World Bank Open Data. Retrieved September 20, 2024 from ',
        link: 'https://data.worldbank.org/indicator/NY.GDP.PCAP.PP.CD',
    },
    {
        text: 'World Bank Group. (2024). Urban population (% of total population). World Bank Open Data. Retrieved September 20, 2024 from ',
        link: 'https://data.worldbank.org/indicator/SP.URB.TOTL.IN.ZS',
    },
];

const dataSourcesDiv = document.querySelector('.data-sources');
const ul = document.createElement('ul');

dataSources.forEach(source => {
    const li = document.createElement('li');
    li.innerHTML = `${source.text}<a href="${source.link}" target="_blank">${source.link}</a>`; 
    ul.appendChild(li);
});

dataSourcesDiv.appendChild(ul);

]]></Code>
</Content>
</Osejs.Model.Initialization.Page>
<Osejs.Model.Initialization.Page>
<Type>undefined</Type>
<Name>readFiles</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
Promise.all([
    readCSVFromPath("annual-co2-emissions-per-country.csv"),
    readCSVFromPath("share-of-population-urban-per-country.csv"),
    readCSVFromPath("gdp-per-capita-ppp.csv"),
    readCSVFromPath("infant-mortality-rate.csv"),
    readCSVFromPath("life-expectancy.csv")
]).then(([annualCO2, urban, gdp, infant, life]) => {
    annualCO2Emissions = annualCO2;
    urbanPopulation = urban;
    gdpPerCapita = gdp;
    infantMortalityRate = infant;
    lifeExpectancy = life;

    generateGraph("year", "urban population");
}).catch(error => {
    console.error("Error loading CSV files:", error);
});


 // const scatterData = {
    //     x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    //     y: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100],
    //     ...type,
    //     name: 'Scatter Data',
    //     marker: { color: 'blue' }
    // };

    // const { slope, intercept } = linearRegression(scatterData.x, scatterData.y);

    // const bestFitY = scatterData.x.map(xi => slope * xi + intercept);

    // const bestFitLine = {
    //     x: scatterData.x,
    //     y: bestFitY,
    //     mode: 'lines',
    //     type: 'scatter',
    //     name: 'Best Fit Line',
    //     line: { color: 'red' }
    // };

    // const layout = {
    //     title: 'Linear Best Fit Line',
    //     margin: { t: 30 },
    //     xaxis: { title: 'X-axis' },
    //     yaxis: { title: 'Y-axis' }
    // };

    // Plotly.newPlot("plot", [scatterData, bestFitLine], layout);
]]></Code>
</Content>
</Osejs.Model.Initialization.Page>
</Osejs.Model.Initialization>
<Osejs.Model.Evolution>
</Osejs.Model.Evolution>
<Osejs.Model.Constraints>
</Osejs.Model.Constraints>
<Osejs.Model.Library>
<Osejs.Model.Library.Page>
<Type>CODE_EDITOR</Type>
<Name>generateGraph</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
function generateGraph(x, y) {
    
    resetBackgroundColors();
    
    //const colorPalette = [
     colorPalette = [
        '#FF6384', // Red
        '#36A2EB', // Blue
        '#FFCE56', // Yellow
        '#4BC0C0', // Teal
        '#9933FF', // Purple
        '#FF9F40', // Orange
        '#FF6347', // Tomato
        '#00FF7F', // Spring Green
        '#FF4500', // Orange Red
        '#8A2BE2', // Blue Violet
        '#FF69B4', // Hot Pink
        '#808080', // Gray 
    ];
    let xAxisData, yAxisData;
    let graphTitle, xAxisTitle, yAxisTitle, xHoverInfoText, yHoverInfoText;
    let xUnit, yUnit; 
    let colorIndex = 0;

    switch (x) {
        case "year":
            xAxisData = 0;
            xAxisTitle = "Year";
            xUnit = "Year"; 
            xHoverInfoText = "Year: ";
            xAxis = "Year";
            break;
        case "annual carbon emissions":
            xAxisData = annualCO2Emissions;
            xAxisTitle = "Annual Carbon Emissions";
            xUnit = "tonnes"; 
            xHoverInfoText = "Annual Carbon Emissions: ";
            xAxis = "Annual Carbon Emissions (tonnes)";
            break;
        case "urban population":
            xAxisData = urbanPopulation;
            xAxisTitle = "Urban Population";
            xUnit = "%"; 
            xHoverInfoText = "Urban Population: ";
            xAxis = "Urban Population (%)";
            break;
        case "gdp per capita":
            xAxisData = gdpPerCapita;
            xAxisTitle = "GDP per capita";
            xUnit = "Intl $"; 
            xHoverInfoText = "GDP per Capita (Intl $): ";
            xAxis = "GDP per capita (adjusted for purchasing power parity, in current international $)";
            break;
        case "infant mortality":
            xAxisData = infantMortalityRate;
            xAxisTitle = "Infant Mortality Rate";
            xUnit = "deaths per 1000 live births"; 
            xHoverInfoText = "Infant Mortality Rate: ";
            xAxis = "Infant Mortality Rate (deaths per 1000 live births)";
            break;
        case "life expectancy":
            xAxisData = lifeExpectancy;
            xAxisTitle = "Life Expectancy at Birth";
            xUnit = "years"; 
            xHoverInfoText = "Life Expectancy at Birth: ";
            xAxis = "Life Expectancy at Birth (years)";
            break;
    }

    switch (y) {
        case "annual carbon emissions":
            yAxisData = annualCO2Emissions;
            xAxisTitle = "Annual Carbon Emissions";
            yUnit = "tonnes"; 
            yHoverInfoText = "Annual Carbon Emissions: ";
            yAxis = "Annual Carbon Emissions (tonnes)";
            break;
        case "urban population":
            yAxisData = urbanPopulation;
            yAxisTitle = "Urban Population";
            yUnit = "%"; 
            yHoverInfoText = "Urban Population: ";
            yAxis = "Urban Population (%)";
            break;
        case "gdp per capita":
            yAxisData = gdpPerCapita;
            yAxisTitle = "GDP per capita";
            yUnit = "Intl $"; 
            yHoverInfoText = "GDP per Capita (Intl $): ";
            yAxis = "GDP per capita (adjusted for purchasing power parity, in current international $)";
            break;
        case "infant mortality":
            yAxisData = infantMortalityRate;
            yAxisTitle = "Infant Mortality Rate";
            yUnit = "deaths per 1000 live births"; 
            yHoverInfoText = "Infant Mortality Rate: ";
            yAxis = "Infant Mortality Rate (deaths per 1000 live births)";
            break;
        case "life expectancy":
            yAxisData = lifeExpectancy;
            yAxisTitle = "Life Expectancy at Birth";
            yUnit = "years"; 
            yHoverInfoText = "Life Expectancy at Birth: ";
            yAxis = "Life Expectancy at Birth (years)";
            break;
    }

    graphTitle = "Graph showing " + yAxisTitle + " against " + xAxisTitle
    
    const traces = [];
    const tempDataX = {};
    const tempDataY = {};

    if (xAxisData === 0) {
        yAxisData.slice(1).forEach(row => {
        const country = row[0];
        const year = parseInt(row[2]);
        const data = parseFloat(row[3]);
    
        if (!tempDataX[country]) {
            tempDataX[country] = { x: [], y: [] };
        }
    
        tempDataX[country].x.push(year);
        tempDataX[country].y.push(data);
        });
        
        for (const country in countriesLookang) {
            if (countriesLookang[country]) {
                
                const traceColor = colorPalette[colorIndex % colorPalette.length];
                colorIndex++;
                
                document.getElementById(formatCountryName(country)).style.backgroundColor = traceColor;                
               
                if (plot !== "best fit") {
                    traces.push({
                        x: tempDataX[country].x,
                        y: tempDataX[country].y,
                        mode: plot,
                        type: "scatter",
                        name: country,
                        marker: { color: traceColor },
                        text: tempDataX[country].x.map((year, index) => `Country: ${country}<br>${yHoverInfoText}${tempDataX[country].y[index]} ${yUnit}<br>${xHoverInfoText}${year}`),
                        hoverinfo: 'text',
                    });
                }
        
                if (plot === "best fit") {
                    const { predictedY, bestFit } = generateBestFitLine(tempDataX[country].x, tempDataX[country].y);
                    traces.push({
                        x: tempDataX[country].x,
                        y: predictedY,
                        mode: 'lines',
                        type: 'scatter',
                        marker: { color: traceColor },
                        name: `${country} Best Fit ${bestFit}`,
                        text: tempDataX[country].x.map((year, index) => `Country: ${country}<br>${yHoverInfoText}${tempDataX[country].y[index]} ${yUnit}<br>${xHoverInfoText}${year}`),
                        hoverinfo: 'text',
                    });
                }
            }
        }
        
        const layout = {
            title: graphTitle,
            xaxis: { 
                title: xAxis,
                rangeslider: {
                    visible: true,
                    range: [Math.min(...yAxisData.slice(1).map(row => parseInt(row[2]))), Math.max(...yAxisData.slice(1).map(row => parseInt(row[2])))]
                },
                type: 'linear'
            },
            yaxis: { title: yAxis },
            margin: { t: 30 }
        };
        
        Plotly.newPlot("plot", traces, layout);
    } else if (x != y) {
        xAxisData.slice(1).forEach(row => {
            const country = row[0];
            const year = parseInt(row[2]);
            const data = parseFloat(row[3]);
    
            if (!tempDataX[country]) {
                tempDataX[country] = {};
            }
            tempDataX[country][year] = data;
        });
    
        yAxisData.slice(1).forEach(row => {
            const country = row[0];
            const year = parseInt(row[2]);
            const data = parseFloat(row[3]);
    
            if (!tempDataY[country]) {
                tempDataY[country] = {};
            }
            tempDataY[country][year] = data;
        });
    
        for (const country in countriesLookang) {
            if (countriesLookang[country]) {
                
                const traceColor = colorPalette[colorIndex % colorPalette.length];
                colorIndex++;

                document.getElementById(formatCountryName(country)).style.backgroundColor = traceColor;                

                const x = [];
                const y = [];
        
                for (const year in tempDataX[country]) {
                    if (tempDataY[country][year] !== undefined) {
                        x.push(tempDataX[country][year]);
                        y.push(tempDataY[country][year]);
                    }
                }
        
                const combinedData = x.map((dataX, index) => ({
                    x: dataX,
                    y: y[index],
                }));
        
                combinedData.sort((a, b) => a.x - b.x);
        
                const sortedX = combinedData.map(data => data.x);
                const sortedY = combinedData.map(data => data.y);
        
                if (plot !== "best fit") {
                    traces.push({
                        x: sortedX,
                        y: sortedY,
                        mode: plot,
                        type: "scatter",
                        marker: { color: traceColor },
                        name: country,
                        text: sortedX.map((dataX, index) => {
                            const year = Object.keys(tempDataX[country]).find(year => tempDataX[country][year] === dataX);
                            return `Country: ${country}<br>${yHoverInfoText}${sortedY[index]} ${yUnit}<br>${xHoverInfoText}${dataX} ${xUnit}<br>Year: ${year}`;
                        }),
                        hoverinfo: 'text',
                    });
                }
        
                if (plot === "best fit") {
                    const { predictedY, bestFit } = generateBestFitLine(sortedX, sortedY);
        
                    traces.push({
                        x: sortedX,
                        y: predictedY,
                        mode: 'lines',
                        type: 'scatter',
                        marker: { color: traceColor },
                        name: `${country} Best Fit ${bestFit}`,
                        text: sortedX.map((dataX, index) => {
                            const year = Object.keys(tempDataX[country]).find(year => tempDataX[country][year] === dataX);
                            return `Country: ${country}<br>${yHoverInfoText}${sortedY[index]} ${yUnit}<br>${xHoverInfoText}${dataX} ${xUnit}<br>Year: ${year}`;
                        }),
                        hoverinfo: 'text',
                    });
                }
            }
        }

        const layout = {
            title: graphTitle,
            xaxis: { title: xAxis },
            yaxis: { title: yAxis },
            margin: { t: 30 }
        };
    
        Plotly.newPlot("plot", traces, layout);
    } else {
        alert("Choose valid x and y axis");
        Plotly.purge('plot');
    }
}

function formatCountryName(countryName) {
    return countryName.toLowerCase().replace(/\s+/g, '_');
}

function resetBackgroundColors() {
    for (let country in countriesLookang) {
        if (countriesLookang.hasOwnProperty(country)) {
            const elementId = formatCountryName(country);
            const element = document.getElementById(elementId);
            if (element) {
                element.style.backgroundColor = "";
            }
        }
    }
}
]]></Code>
</Content>
</Osejs.Model.Library.Page>
<Osejs.Model.Library.Page>
<Type>CODE_EDITOR</Type>
<Name>bestFitLine</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
function generateBestFitLine(xValues, yValues) {
    function calculateRSquared(observed, predicted) {
        const mean = observed.reduce((sum, val) => sum + val) / observed.length;
        const ssTot = observed.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0);
        const ssRes = observed.reduce((sum, val, index) => sum + Math.pow(val - predicted[index], 2), 0);
        return 1 - (ssRes / ssTot);
    }

    function linearRegression(x, y) {
        const n = x.length;
        const sumX = x.reduce((sum, val) => sum + val, 0);
        const sumY = y.reduce((sum, val) => sum + val, 0);
        const sumXY = x.reduce((sum, val, index) => sum + val * y[index], 0);
        const sumX2 = x.reduce((sum, val) => sum + val * val, 0);
        const slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
        const intercept = (sumY - slope * sumX) / n;
        const predicted = x.map(val => slope * val + intercept);
        return { rSquared: calculateRSquared(y, predicted), predicted };
    }

    function exponentialRegression(x, y) {
        const logY = y.map(Math.log);
        const { rSquared, predicted } = linearRegression(x, logY);
        const exponentialPredicted = predicted.map(val => Math.exp(val)); // convert back
        return { rSquared, predicted: exponentialPredicted };
    }

    function polynomialRegression(x, y, degree = 2) {
        const n = x.length;
        const X = Array.from({ length: n }, () => Array(degree + 1).fill(0));
    
        for (let i = 0; i < n; i++) {
            for (let j = 0; j <= degree; j++) {
                X[i][j] = Math.pow(x[i], j);
            }
        }
    
        const XtX = math.multiply(math.transpose(X), X); 
        const XtY = math.multiply(math.transpose(X), y); 
        const invXtX = math.inv(XtX);
        const coeffs = math.multiply(invXtX, XtY); 
    
        const predicted = x.map(val => 
            coeffs.reduce((sum, coeff, idx) => sum + coeff * Math.pow(val, idx), 0)
        );
        
        return { rSquared: calculateRSquared(y, predicted), predicted };
    }

    function powerRegression(x, y) {
        const logX = x.map(Math.log);
        const logY = y.map(Math.log);
        const { rSquared, predicted } = linearRegression(logX, logY);
        const powerPredicted = predicted.map(val => Math.exp(val)); 
        return { rSquared, predicted: powerPredicted };
    }

    const linearFit = linearRegression(xValues, yValues);
    const exponentialFit = exponentialRegression(xValues, yValues);
    const polynomialFit = polynomialRegression(xValues, yValues);
    const powerFit = powerRegression(xValues, yValues);

    const fits = [
        { type: 'Linear', rSquared: linearFit.rSquared, predicted: linearFit.predicted },
        { type: 'Exponential', rSquared: exponentialFit.rSquared, predicted: exponentialFit.predicted },
        { type: 'Polynomial', rSquared: polynomialFit.rSquared, predicted: polynomialFit.predicted },
        { type: 'Power', rSquared: powerFit.rSquared, predicted: powerFit.predicted },
    ];

    const bestFit = fits.reduce((best, current) => (current.rSquared > best.rSquared ? current : best));

    return {
        bestFit: bestFit.type,
        rSquared: bestFit.rSquared,
        predictedY: bestFit.predicted,
        predictedX: xValues, 
    };
}
]]></Code>
</Content>
</Osejs.Model.Library.Page>
<Osejs.Model.Library.Page>
<Type>CODE_EDITOR</Type>
<Name>readCsv</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
function readCSVFromPath(path) {
    //return fetch('https://webejs.iwant2study.org:8000/static/sessions/4252cf9e-0bb7-45e2-82b1-d87c44464c7d/source/' + path)  // Replace 'yourfile.csv' with the actual file name
    return fetch('./' + path)  // Replace 'yourfile.csv' with the actual file name
        .then(response => {
            if (!response.ok) {
                throw new Error("Failed to fetch the CSV file");
            }
            return response.text();  // Return the CSV content as plain text
        })
        .then(data => {
            const parsedData = parseCSV(data);  // Parse the CSV data
            return parsedData;
        })
        .catch(error => {
            console.error("Error reading the CSV file:", error);
        });
}

function parseCSV(csvText) {
    const rows = csvText.split("\n").filter(row => row.trim() !== "");  
    const result = rows.map(row => row.split(",").map(value => value.trim().replace(/\r$/, ""))); 
    return result;
}

]]></Code>
</Content>
</Osejs.Model.Library.Page>
<Osejs.Model.Library.Page>
<Type>CODE_EDITOR</Type>
<Name>lookang</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<Comment><![CDATA[]]></Comment>
<Code><![CDATA[
function updateSelectAllCheckboxState() {
    selectAll = Object.values(countriesLookang).every(checked => checked === true);

    if (selectAll) {
        for (const country in countriesLookang) {
            countriesLookang[country] = selectAll;
        }
    }
}

function onClickCheckBox (country) {
    countriesLookang[country] = !countriesLookang[country];
    generateGraph(currentX, currentY);
    updateSelectAllCheckboxState();
}

function onClickSelectAll() {
    for (const country in countriesLookang) {
        countriesLookang[country] = selectAll;
    }
    generateGraph(currentX, currentY);
}
]]></Code>
</Content>
</Osejs.Model.Library.Page>
</Osejs.Model.Library>
<Osejs.Model.Elements>
</Osejs.Model.Elements>
</Osejs.Model>
<Osejs.HtmlView>
<Osejs.HtmlView.Page>
<Type>HTML_VIEW_EDITOR</Type>
<Name>HtmlView</Name>
<Active>true</Active>
<Internal>false</Internal>
<Content>
<SizeOption>0</SizeOption>
<X>0</X>
<Y>0</Y>
<Width>800</Width>
<Height>600</Height>
<KeepHidden>true</KeepHidden>
<RootProperties>
</RootProperties>
<Tree>
<HtmlView.Element>
<Expanded>true</Expanded>
<Type>Elements.Panel</Type>
<Name><![CDATA[panel]]></Name>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.Panel</Type>
<Name><![CDATA[plot]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="ClassName"><![CDATA["plot"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.Label</Type>
<Name><![CDATA[X_Axis]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="Text"><![CDATA["X Axis"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.ComboBox</Type>
<Name><![CDATA[xAxis]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="Options"><![CDATA[["year", "annual carbon emissions", "urban population", "gdp per capita", "infant mortality", "life expectancy"]]]></Property>
<Property name="OnChange"><![CDATA[var opts = _view.xAxis.getProperty("SelectedOptions");  
var option = (opts.length > 0)? opts[0]:"";
currentX = option;
generateGraph(currentX, currentY);]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.Label</Type>
<Name><![CDATA[Y_Axis]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="Text"><![CDATA["Y Axis"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.ComboBox</Type>
<Name><![CDATA[yAxis]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="Options"><![CDATA[["urban population", "annual carbon emissions", "gdp per capita", "infant mortality", "life expectancy"]]]></Property>
<Property name="OnChange"><![CDATA[var opts = _view.yAxis.getProperty("SelectedOptions");  
var option = (opts.length > 0)? opts[0]:"";
currentY = option;
generateGraph(currentX, currentY);]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.ComboBox</Type>
<Name><![CDATA[scatter_line]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="CSS"><![CDATA["{margin-left: 10px;}"]]></Property>
<Property name="Options"><![CDATA[["line", "scatter", "best fit"]]]></Property>
<Property name="OnChange"><![CDATA[var opts = _view.scatter_line.getProperty("SelectedOptions");  
var option = (opts.length > 0)? opts[0]:"";
plot = option === "line" ? "lines" : option === "scatter" ? "markers" : option === "best fit" ? "best fit" : undefined;
generateGraph(currentX, currentY);]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Expanded>true</Expanded>
<Type>Elements.Panel</Type>
<Name><![CDATA[selectAll]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="ClassName"><![CDATA["select-all"]]></Property>
<Property name="CSS"><![CDATA["
{
margin-top: 15px;
}
"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[selectAllCheckbox]]></Name>
<Parent><![CDATA[selectAll]]></Parent>
<Property name="Text"><![CDATA["Select All"]]></Property>
<Property name="Checked"><![CDATA[selectAll]]></Property>
<Property name="OnChange"><![CDATA[onClickSelectAll()]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Expanded>true</Expanded>
<Type>Elements.Panel</Type>
<Name><![CDATA[wrapper]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="CSS"><![CDATA["
{
display: flex;
align-items:center;
}
"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Expanded>true</Expanded>
<Type>Elements.Panel</Type>
<Name><![CDATA[selectCountry]]></Name>
<Parent><![CDATA[wrapper]]></Parent>
<Property name="ClassName"><![CDATA["countries"]]></Property>
<Property name="CSS"><![CDATA["{
    display: flex;             
    flex-wrap: wrap;          
    gap: 10px;                
    max-width: 100%;          
    overflow: hidden;         
}"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[brunei]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Brunei"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Brunei"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Brunei")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[cambodia]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Cambodia"]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Cambodia")]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Cambodia"]]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[east_timor]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["East Timor"]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("East Timor")]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["East Timor"]]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[indonesia]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Indonesia"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Indonesia"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Indonesia")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[laos]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Laos"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Laos"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Laos")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[malaysia]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Malaysia"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Malaysia"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Malaysia")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[myanmar]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Myanmar"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Myanmar"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Myanmar")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[philippines]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Philippines"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Philippines"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Philippines")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[singapore]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Singapore"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Singapore"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Singapore")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[thailand]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Thailand"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Thailand"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Thailand")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[vietnam]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["Vietnam"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["Vietnam"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("Vietnam")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.CheckBox</Type>
<Name><![CDATA[world]]></Name>
<Parent><![CDATA[selectCountry]]></Parent>
<Property name="Text"><![CDATA["World"]]></Property>
<Property name="Checked"><![CDATA[countriesLookang["World"]]]></Property>
<Property name="OnChange"><![CDATA[onClickCheckBox("World")]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.Label</Type>
<Name><![CDATA[references]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="Text"><![CDATA["References"]]></Property>
<Property name="CSS"><![CDATA["
{
 margin-top: 30px;
    font-size: 24px; 
    font-weight: bold; 
    color: #333; 
    text-align: left;
    border-bottom: 2px solid #ddd; 
    padding-bottom: 10px;
}
"]]></Property>
</HtmlView.Element>
<HtmlView.Element>
<Type>Elements.Panel</Type>
<Name><![CDATA[dataScources]]></Name>
<Parent><![CDATA[panel]]></Parent>
<Property name="ClassName"><![CDATA["data-sources"]]></Property>
</HtmlView.Element>
</Tree>
</Content>
</Osejs.HtmlView.Page>
</Osejs.HtmlView>
</Osejs>