<?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[]]></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;./math.js;./lib/math.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[sliderMin]]></Name>
<Value><![CDATA[0]]></Value>
<Type><![CDATA[double]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[sliderMax]]></Name>
<Value><![CDATA[0]]></Value>
<Type><![CDATA[double]]></Type>
<Dimension><![CDATA[]]></Dimension>
<Domain><![CDATA[]]></Domain>
<Comment><![CDATA[]]></Comment>
</Variable>
<Variable>
<Name><![CDATA[pathId]]></Name>
<Value><![CDATA["e6711dec-dde7-4193-8157-df8edbd7e4e4"]]></Value>
<Type><![CDATA[String]]></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[
//initialize countries
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[
//initialize datasources
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',
    },
];

//populate div with classname "data-sources" with the dataSources Object
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[
// read all the files and set the variables with the read data
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[
//generate graph function
function generateGraph(x, y) {
    
    //reset checkbox background color everytime new option is selected
  resetBackgroundColors();

  //const colorPalette = [
  colorPalette = [
    '#D81B60', // Pink
    '#1E88E5', // Blue
    '#FFC107', // Yellow
    '#004D40', // Teal
    '#6A1B9A', // Deep Purple
    '#FF9F40', // Orange
    '#2E7D32', // Green
    '#795548', // Brown
    '#C62828', // Red
    '#00ACC1', // Cyan
    '#4E342E', // Dark Brown
    '#757575', // Gray
  ];
  const config = {
    displayModeBar: false
  };
  //declare variables for the graph
  let xAxisData, yAxisData;
  let graphTitle, xAxisTitle, yAxisTitle, xHoverInfoText, yHoverInfoText;
  let xUnit, yUnit;
  let colorIndex = 0;

    //configuration to set data for x y axis and graph configurations
  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;
      yAxisTitle = "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

    //declare traces and plot points for x and y axis
  const traces = [];
  const tempDataX = {};
  const tempDataY = {};

    //if x axis is year plot like this and include range slider
  if (xAxisData === 0) {
      
      //separate data and get the values for each country in that year
    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);
    });

    //plot the traces for countries selected
    for (const country in countriesLookang) {
      if (countriesLookang[country]) {

        //trace color
        const traceColor = colorPalette[colorIndex % colorPalette.length];
        colorIndex++;

        document.getElementById(formatCountryName(country)).style.backgroundColor = traceColor;
         //for border style
        // document.getElementById(formatCountryName(country)).style.borderColor = traceColor;
        // document.getElementById(formatCountryName(country)).style.borderWidth = "2px"; 
        // document.getElementById(formatCountryName(country)).style.borderStyle = "solid"; 
        
        //if plot is scatter or straight line
        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 is best fit
        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',
          });
        }
      }
    }

    //configuration for the range slider
    const minYear = Math.min(...yAxisData.slice(1).map(row => parseInt(row[2])));
    const maxYear = Math.max(...yAxisData.slice(1).map(row => parseInt(row[2])));

    const yearAnnotations = [minYear];
    const step = (maxYear - minYear) / 6;

    for (let i = 1; i < 6; i++) {
      const year = Math.round(minYear + step * i);
      yearAnnotations.push(year);
    }
    yearAnnotations.push(maxYear);

    const annotations = yearAnnotations.map((year, index) => ({
      xref: 'paper',
      yref: 'paper',
      x: index / 6,
      y: -0.22,
      xanchor: 'center',
      yanchor: 'top',
      text: year.toString(),
      showarrow: false,
      font: { size: 12 }
    }));

    //layout for the graph
    const layout = {
      title: graphTitle,
      xaxis: {
        title: xAxis,
        rangeslider: {
          thickness: 0.08,
          bgcolor: 'rgba(0, 162, 255, 0.2)',
          //   bordercolor: '#444',
          borderwidth: 2,
          yaxis: {
            rangemode: 'fixed',
            // yes this is to prevent the lines from being shown in slider and make sure the color of bar is consistent, very weird but works
            range: [1000000000000000000000000000, 1000000000000000000000000000]
          },
        },
        type: 'linear',
        range: [sliderMin || Math.min(...yAxisData.slice(1).map(row => parseInt(row[2]))), sliderMax || Math.max(...yAxisData.slice(1).map(row => parseInt(row[2])))],
        // autorange: true, fixedrange: false, zeroline: false,
      },
      yaxis: { title: yAxis, autorange: true, fixedrange: false, zeroline: false },
      margin: { t: 30, b: 100 },
      annotations: annotations,
      shapes: [
        {
          type: 'line',
          x0: 0, x1: 1, y0: 0, y1: 0,
          xref: 'paper', yref: 'paper',
          line: { color: 'black', width: 1 }
        },
        {
          type: 'line',
          x0: 0, x1: 0, y0: 0, y1: 1,
          xref: 'paper', yref: 'paper',
          line: { color: 'black', width: 1 }
        }
      ]
    };
    //plot the graph
    Plotly.newPlot("plot", traces, layout, config).then((gd) => {
      gd.on('plotly_relayout', function (eventData) {
        if (eventData['xaxis.range']) {
          storeCurrentRange(eventData);
        }
      });
    });
    //all the other plots
  } else if (x != y) {
    //separate x and y data and get the values for each country in that year
    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;
    });

        //trace color
    for (const country in countriesLookang) {
      if (countriesLookang[country]) {

        const traceColor = colorPalette[colorIndex % colorPalette.length];
        colorIndex++;

        document.getElementById(formatCountryName(country)).style.backgroundColor = traceColor;
         //for border style
        // document.getElementById(formatCountryName(country)).style.borderColor = traceColor;
        // document.getElementById(formatCountryName(country)).style.borderWidth = "2px"; 
        // document.getElementById(formatCountryName(country)).style.borderStyle = "solid"; 

        const x = [];
        const y = [];

        //combine the data joining them based on year and country
        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 is scatter or straight line
        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 is best fit
        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',
          });
        }
      }
    }
    //layout for the graph
    const layout = {
      title: graphTitle,
      xaxis: { title: xAxis, range: [0, yAxisTitle === "Urban Population" ? 100 : null], autorange: true, fixedrange: false, zeroline: false },
      yaxis: { title: yAxis, range: [0, null], autorange: true, fixedrange: false, zeroline: false },
      margin: { t: 30 },
      shapes: [
        {
          type: 'line',
          x0: 0, x1: 1, y0: 0, y1: 0,
          xref: 'paper', yref: 'paper',
          line: { color: 'black', width: 1 }
        },
        {
          type: 'line',
          x0: 0, x1: 0, y0: 0, y1: 1,
          xref: 'paper', yref: 'paper',
          line: { color: 'black', width: 1 }
        }
      ]
    };
    //plot the graph
    Plotly.newPlot("plot", traces, layout, config);
  } 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 = "";
      }
    }
  }
}

function storeCurrentRange(eventData) {
  const currentLayout = eventData['xaxis.range'];
  if (currentLayout) {
    sliderMin = currentLayout[0];
    sliderMax = currentLayout[1];
  } else {
    console.error("Failed to store range, eventData invalid");
  }
}

]]></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[
//generate bestfitline
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[
//read csv
function readCSVFromPath(path) {
    return fetch(pathId ? `https://webejs.iwant2study.org:8000/static/sessions/${pathId}/source/${path}` : `./${path}`)
        .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[
//on click functions for checkbox buttons
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;
sliderMax = 0;
sliderMin = 0;
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;
sliderMin = 0;
sliderMax = 0;
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>false</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>false</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>