Phone:

+(39) 340 0055844

Email:

giampio.cavallo@gmail.com

© 2023 Giampio Cavallo
All rights reserved

Client:

Generation Italy

Services:

Dashboard & Forecast

Duration:

1 month



Card Image


Development: 09/04/2023 – 10/05/2023



Project Introduction


Ecochart is a portal designed for those who are new to the field of economics, aimed at providing a clear and intuitive explanation of the Italian economic situation. Using interactive charts and machine learning algorithms, it presents historical data and forecasts on key economic indicators, along with insights to facilitate learning.




Project Objectives


Accessing economic data and forecasts can be complex and unintuitive for those who are not experts in the field of economics. "Ecochart" has been created to address this issue by providing a user-friendly interface for exploring key economic data in Italy.




Project Objectives


The main objectives of "Ecochart" are:
● Gather reliable economic data from open-source sources.
● Present data engagingly through interactive charts.
● Calculate forecasts on the future trends of the Italian economy using machine learning.




Technologies Used


● Python's Flask framework for web development.
● MySQL database managed through XAMPP.
● MySQL-Connector library for database connection.
● Python's StatsModel library for future trend prediction.
● Chart.JS library for creating interactive charts on the website.
● DataTables library for tabular data on the portal.
● Power BI for additional visual representation of historical series under examination.
● JavaScript, JQuery, Bootstrap, CSS, HTML-5 for a modern and interactive look.




Demo Source-Code (Front-end)


 
        <!DOCTYPE html>
        <html lang="en">

        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
            <title>ECOCHART</title>
            <meta name="description" content="ECOCHART">
            <link rel="stylesheet" href="./static/assets/bootstrap/css/bootstrap.min.css">
            <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:400,400i,700,700i,600,600i&display=swap">
            <link rel="stylesheet" href="./static/assets/fonts/simple-line-icons.min.css">
            <link rel="stylesheet" href="./static/assets/css/baguetteBox.min.css">
            <link rel="stylesheet" href="./static/assets/css/vanilla-zoom.min.css">
            <script src="./static/assets/js/plotly-2.20.0.min.js"></script>
            <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
        </head>
        <body>
        <style>
    /* Utilizziamo il font sans-serif di sistema come fallback */
    /* Potrebbe essere necessario sostituire i nomi dei font a seconda della piattaforma e dei font installati */
    @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap');

    .carousel-item {
      position: relative;
    }

    .carousel-caption {
      position: absolute;
      top: 50%;
      right: 0;
      transform: translateY(-50%);
      background-color: #f7e1a6;
      padding: 20px;
      width: 300px;
      height: 300px;
      cursor: pointer;
      display: flex;
      justify-content: flex-start;
      align-items: center;
      flex-direction: column;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
      font-family: 'Montserrat', sans-serif; /* Applichiamo il font personalizzato */
    }

    .carousel-caption h4, .carousel-caption p {
      color: black;
    }


    .carousel-caption h4 {
      font-size: 32px; /* Aumentiamo la dimensione del font per attirare l'attenzione */
      margin-top: 30px;
      margin-bottom: 10px; /* Ripristiniamo il margine a 10px */
      font-weight: 700; /* Utilizziamo il font in grassetto */
      text-transform: uppercase; /* Modifichiamo il testo in maiuscolo per enfatizzare il titolo */
    }

    .carousel-caption p {
      font-size: 16px; /* Aumentiamo la dimensione del font per renderlo più leggibile */
      margin-top: 10px;
      margin-bottom: 0;
      overflow-wrap: break-word;
      word-wrap: break-word;
      white-space: normal;
      font-weight: 400; /* Utilizziamo il font normale per il testo della descrizione */
      line-height: 1.4; /* Aumentiamo l'interlinea per migliorare la leggibilità */
    }
</style>
        <script>
        var captions = document.querySelectorAll('.carousel-caption');
        captions.forEach(function(caption) {
          caption.addEventListener('click', function() {
            window.location.href = "http://www.paginaweb.com";
          });
        });
        </script>
        </head>
        <body>
        <nav class="navbar navbar-light navbar-expand-lg fixed-top bg-white clean-navbar">
        <div class="container"><a class="navbar-brand logo" href="#">ECOCHART</a><button data-bs-toggle="collapse" class="navbar-toggler" data-bs-target="#navcol-1"><span class="visually-hidden">Toggle navigation</span><span class="navbar-toggler-icon"></span></button>
        <div class="collapse navbar-collapse" id="navcol-1">
        <ul class="navbar-nav ms-auto">
        <li class="nav-item"><a class="nav-link active" href="/">Home</a></li>
        <li class="nav-item"><a class="nav-link" href="/service_page">Analisi</a></li>
        <li class="nav-item"><a class="nav-link" href="/faq">FAQ</a></li>
        <li class="nav-item"><a class="nav-link" href="/blog_post_list">Notizie</a></li>
        <li class="nav-item"><a class="nav-link" href="/about_us">Chi Siamo</a></li>
        </ul>
        </div>
        </div>
        </nav>
        <main class="page landing-page">
        <section class="clean-block clean-hero" style="background-image: url("./static/assets/img/tech/pippobaudo.jpg");color: rgba(9, 162, 255, 0.85);">
        <div class="text">
        <h1 class="display-2">ECOCHART</h1>
        <p> l'applicazione per conoscere e analizzare l'economia italiana</p>
        </div>
        </section>
        <section class="clean-block clean-info dark">
        <div class="container">
        <div class="block-heading">
        <h2 class="text-info">Info</h2>
        <p style="display: inline;">Ecochart è l'applicazione web che offre agli utenti un'analisi completa dell'economia italiana, aiutandoli a comprendere meglio la situazione attuale e a prendere decisioni informate sugli investimenti e sulle attività economiche. Grazie a un'interfaccia intuitiva e facile da usare, gli utenti possono accedere a dati aggiornati su PIL, disoccupazione, inflazione e altre statistiche economiche, nonché a previsioni future.</p>
        </div>
        <div class="row align-items-center">
        <div class="col-md-6"><img src="./static/assets/img/tech/luke-chesser-JKUTrJ4vK00-unsplash.jpg" style="width: 626px; height: 417px; box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);"></div>
        <div class="col-md-6">
        <h3>Strumenti di Analisi Avanzati</h3>
        <div class="getting-started-info">
        <p>aiutiamo gli utenti a prendere decisioni informate sulle attività economiche, fornendo informazioni essenziali sulla situazione attuale e futura dell'economia italiana.</p>
        </div><button class="btn btn-outline-primary btn-lg" type="button" onclick="window.location.href='/service_page'">CLICCA QUI</button>
        </div>
        </div>
        </div>

        </section>
        <section class="clean-block features">
        <div class="container">
        <div class="block-heading">
        <h2 class="text-info">Servizi</h2>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quam urna, dignissim nec auctor in, mattis vitae leo.</p>
        </div>
        <div class="row justify-content-center">
        <div class="col-md-5 feature-box"><i class="icon-star icon"></i>
        <h4>Dati economici aggiornati</h4>
        <p>offriamo dati aggiornati sull'economia italiana, tra cui il PIL, la disoccupazione e l'inflazione.</p>
        </div>
        <div class="col-md-5 feature-box"><i class="icon-pencil icon"></i>
        <h4>Dashboard Interattive</h4>
        <p>permettono di visualizzare facilmente e intuitivamente i dati, rendendo più accessibile l'informazione economica anche ai non addetti ai lavori</p>
        </div>
        <div class="col-md-5 feature-box"><i class="icon-screen-smartphone icon"></i>
        <h4>Confronto di statistiche</h4>
        <p>permette di visualizzare e confrontare statistiche economiche a livello nazionale</p>
        </div>
        <div class="col-md-5 feature-box"><i class="icon-refresh icon"></i>
        <h4>Previsioni future</h4>
        <p>ECOCHART consente di accedere a previsioni future sull'andamento dell'economia italiana, basate su modelli statistici e analisi di trend</p>
        </div>
        </div>
        </div>
        </section>
        <section class="clean-block slider dark">
        <div class="container">
        <div class="block-heading">
        <h2 class="text-info"><a href="/blog_post_list" style="text-decoration:none; color:inherit;">Notizie</a></h2>
        <p>di seguito vi proponiamo gli aggiornamenti quotidiani sull'economia nazionale e internazionale</p>
        </div>
        <div class="carousel slide" data-bs-ride="carousel" id="carousel-1">
        <div class="carousel-inner">
        <div class="carousel-item active">
        <img class="w-100 d-block" src="./static/assets/img/scenery/img1.jpg" alt="Slide Image">
        <div class="carousel-caption">
        <h4><a href="https://mercati.ilsole24ore.com/dati-macroeconomici/paesi-a-confronto/previsione-economica" class="custom-link">il sole 24ore</a></h4>
        <p>Tratta una vasta gamma di notizie in ambito economico, finanziario e politico, con particolare attenzione al mercato italiano ed europeo.</p>
        </div>
        </div>
        <div class="carousel-item">
        <img class="w-100 d-block" src="./static/assets/img/scenery/img2.jpg" alt="Slide Image">
        <div class="carousel-caption">
        <h4><a href="https://www.ft.com" class="custom-link">Financial Times</a></h4>
        <p>Copre notizie finanziarie, economiche e politiche a livello internazionale, offrendo un'analisi approfondita dei mercati e delle tendenze economiche. </p>
        </div>
        </div>
        <div class="carousel-item">
        <img class="w-100 d-block" src="./static/assets/img/scenery/img3.jpg" alt="Slide Image">
        <div class="carousel-caption">
        <h4><a href="https://asia.nikkei.com/" class="custom-link">Nikkei</a></h4>
        <p>Giornale giapponese che copre notizie economiche, finanziarie e politiche della regione asiatica</p>
        </div>
        </div>
        </div>
        <a class="carousel-control-prev" href="#carousel-1" role="button" data-bs-slide="prev">
        <span class="carousel-control-prev-icon"></span>
        <span class="visually-hidden">Previous</span>
        </a>
        <a class="carousel-control-next" href="#carousel-1" role="button" data-bs-slide="next">
        <span class="carousel-control-next-icon"></span>
        <span class="visually-hidden">Next</span>
        </a>
        <ol class="carousel-indicators">
        <li data-bs-target="#carousel-1" data-bs-slide-to="0" class="active"></li>
        <li data-bs-target="#carousel-1" data-bs-slide-to="1"></li>
        <li data-bs-target="#carousel-1" data-bs-slide-to="2"></li>
        </ol>
        </div>
        </div>
        </section>

       # esempio di codice per un nostro grafico
        <script>
        function showChart() {
          // Chiamata AJAX per recuperare i dati del grafico
          fetch('/data')
            .then(response => response.json())
            .then(data => {
              // Nascondi il container del grafico 1 e mostra il container del grafico 2
              document.getElementById('chart-container').style.display = 'block';
              document.getElementById('chart-container1').style.display = 'none';
              document.getElementById('chart-container2').style.display = 'none';
              document.getElementById('chart-container3').style.display = 'none';
              document.getElementById('chart-container4').style.display = 'none';
              document.getElementById('chart-container5').style.display = 'none';

              // Rimuovi il contenuto precedente del container del grafico
              document.getElementById('chart-container').innerHTML = '';

              // Crea il canvas per il grafico
              var canvas = document.createElement('canvas');
              canvas.setAttribute('id', 'myChart');
              document.getElementById('chart-container').appendChild(canvas);

              // Crea il grafico
              var ctx = canvas.getContext('2d');
              // Crea i gradienti per i colori
              var gradientBlue = canvas.getContext('2d').createLinearGradient(0, 0, 0, 450);
              gradientBlue.addColorStop(0, 'rgba(0, 162, 255, 1)'); // azzurro
              gradientBlue.addColorStop(0.5, 'rgba(0, 100, 200, 1)'); // blu
              gradientBlue.addColorStop(1, 'rgba(0, 50, 100, 1)'); // blu scuro

              var gradientWhiteGray = canvas.getContext('2d').createLinearGradient(0, 0, 0, 450);
              gradientWhiteGray.addColorStop(0, 'rgba(255, 255, 255, 1)'); // bianco
              gradientWhiteGray.addColorStop(0.5, 'rgba(200, 200, 200, 1)'); // grigio medio
              gradientWhiteGray.addColorStop(1, 'rgba(100, 100, 100, 1)'); // grigio scuro

              // Crea il grafico
              var chart = new Chart(canvas, {
                type: 'line',
                data: {
                  labels: data.map(item => item.label),
                  datasets: [{
                    label: 'Debito / PIL',
                    data: data.map(item => item.value),
                    backgroundColor: data.map(item => item.label <= 2022 ? gradientBlue : gradientWhiteGray),
                    borderColor: data.map(item => item.label <= 2022 ? gradientBlue : gradientWhiteGray),
                    borderWidth: 3,
                    pointBackgroundColor: data.map(item => item.label <= 2022 ? gradientBlue : gradientWhiteGray),
                    pointHoverBackgroundColor: data.map(item => item.label <= 2022 ? gradientBlue : gradientWhiteGray),
                    pointBorderColor: data.map(item => item.label <= 2022 ? gradientBlue : 'rgba(200, 99, 132, 1)'),
                    pointBorderWidth: data.map(item => item.label <= 2022 ? 3 : 3),
                    pointRadius: data.map(item => item.label <= 2022 ? 6 : 6),
                    pointHoverRadius: data.map(item => item.label <= 2022 ? 8 : 8),
                  }]
                },
                options: {
                  scales: {
                    yAxes: [{
                      ticks: {
                        beginAtZero: true
                      }
                    }]
                  },
                  plugins: {
                    zoom: {
                      zoom: {
                        wheel: {
                          enabled: true,
                        },
                        mode: 'x',
                      },
                      pan: {
                        enabled: true,
                        mode: 'x'
                      }
                    },
                    annotation: {
                      annotations: [{
                        type: 'line',
                        mode: 'vertical',
                        scaleID: 'x-axis-0',
                        yScaleID: 'y-axis-0',
                        xMin: '2023',
                        xMax: '2023',
                        yMin: 160,
                        yMax: 160,
                        value: '2023',
                        borderColor: 'grey',
                        borderWidth: 1,
                        label: {
                          content: 'Forecast',
                          enabled: true,
                          position: 'top'
                        }
                      }]
                    }
                  },
                  legend: {
                    labels: {
                      fontColor: 'black',
                      fontSize: 16,
                      fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"
                    }
                  },
                  onClick: function(event, elements) {
                    if (elements.length > 0) {
                      var elementIndex = elements[0]._index;
                      var datasetIndex = elements[0]._datasetIndex;
                      chart.setDatasetVisibility(datasetIndex, false);
                      chart.update();
                      setTimeout(function() {
                        chart.setDatasetVisibility(datasetIndex, true);
                        chart.update();
                      }, 3000);
                    }
                  }
                }
              });

              // Aggiungi un tag br per creare una riga vuota
              var lineBreak = document.createElement('br');
              document.getElementById('chart-container').appendChild(lineBreak);

              // Aggiungi un tag br per creare una riga vuota
              var lineBreak = document.createElement('br');
              document.getElementById('chart-container').appendChild(lineBreak);

              // Crea il paragrafo di presentazione del grafico
              var description = document.createElement('p');
              description.innerHTML = 'Il Debito/PIL è un indicatore che esprime il rapporto tra il debito pubblico di un paese e il suo PIL, utilizzato per valutare la capacità di un paese di ripagare il proprio debito. I dati rappresentati sono relativi al periodo 1988-2028 e sono espressi in percentuale.';
              description.style.textAlign = 'center';
              description.style.color = 'gray';
              document.getElementById('chart-container').appendChild(description);

              // Aggiungi un tag br per creare una riga vuota
              var lineBreak = document.createElement('br');
              document.getElementById('chart-container').appendChild(lineBreak);

              // Aggiungi un tag br per creare una riga vuota
              var lineBreak = document.createElement('br');
              document.getElementById('chart-container').appendChild(lineBreak);
            });
        }
        </script>
    


Architecture and Design


The project utilizes the Flask framework to host locally, along with a MariaDB from XAMPP to store data. This data has been collected from reliable sources and subsequently processed and cleaned. The visual aspect has been created using Bootstrap CSS, HTML-5, and JavaScript elements to ensure a clean and intuitive user experience.




Demo Source-Code (Back-end)


    
from flask import Flask, render_template, jsonify
import csv
import mysql.connector


per=r"C:\Users\file.csv"

lista1 = []
lista2 = []
lista3 = []
lista4 = []
lista5 = []
lista6 = []

with open(per,encoding='utf-8') as filecsv:
    lettore = csv.reader(filecsv,delimiter=';')
    next(lettore)
    for riga in lettore:
        lista1.append((riga[0], riga[1]))
        lista2.append((riga[0], riga[2]))
        lista3.append((riga[0], riga[3]))
        lista4.append((riga[0], riga[4]))
        lista5.append((riga[0], riga[5]))
        lista6.append((riga[0], riga[6]))

for i in range(len(lista1)):
    lista1[i] = (lista1[i][0], lista1[i][1].replace(',', '.'))

for i in range(len(lista2)):
    lista2[i] = (lista2[i][0], lista2[i][1].replace(',', '.'))

for i in range(len(lista3)):
    lista3[i] = (lista3[i][0], lista3[i][1].replace(',', '.'))

for i in range(len(lista4)):
    lista4[i] = (lista4[i][0], lista4[i][1].replace(',', '.'))

for i in range(len(lista5)):
    lista5[i] = (lista5[i][0], lista5[i][1].replace(',', '.'))

for i in range(len(lista6)):
    lista6[i] = (lista6[i][0], lista6[i][1].replace(',', '.'))

for i, val in enumerate(lista1):
    if val[1] == '':
        lista1[i] = val[:1] + (None,)

for i, val in enumerate(lista1):
    if val[1] is None:
        continue
    lista1[i] = (val[0], float(val[1]))


mydb = mysql.connector.connect(
    host = 'XXX',
    user = 'XXX',
    password = 'XXX'
)
mycursor = mydb.cursor()

mycursor.execute("CREATE DATABASE IF NOT EXISTS Ecochart;")
mycursor.execute("USE Ecochart;")

mycursor.execute("DROP TABLE debpil;")
mycursor.execute("CREATE TABLE IF NOT EXISTS debpil (anno INT,debitopil FLOAT);")
mycursor.executemany("INSERT IGNORE INTO debpil(anno, debitopil) VALUES(%s,%s);",lista1)
mydb.commit()
# Esegui una query per selezionare i dati che ti servono
mycursor.execute("SELECT anno, debitopil FROM debpil")
# Recupera i dati e crea la lista di dizionari
data = []
for anno, debitopil in mycursor:
    if debitopil is not None:
        data.append({
            "label": str(anno),
            "value": float(debitopil)
        })
    else:
        data.append({
            "label": str(anno),
            "value": None
        })


#mycursor.execute("DROP TABLE INFLAZIONE;")
mycursor.execute("CREATE TABLE if not exists inflazione(anno INT,infl FLOAT);")
mycursor.executemany("INSERT ignore INTO inflazione(anno, infl) VALUES(%s,%s);",lista2)
mydb.commit()


#mycursor.execute("DROP TABLE BILANCIA;")
mycursor.execute("CREATE TABLE if not exists bilancia(anno INT,bil FLOAT);")
mycursor.executemany("INSERT ignore INTO BILANCIA(anno, bil) VALUES(%s,%s);",lista3)
mydb.commit()


# Route per il grafico sul rapporto debito/pil
# Jsonify perchè Chart.js necessita di questo formato

@app.route('/data')
def get_data():
    mydb = mysql.connector.connect(
        host = 'XXX',
        user = 'XXX',
        password = 'XXX'
    )
    mycursor = mydb.cursor()

    mycursor.execute("USE Ecochart;")
    mycursor.execute("SELECT distinct anno, debitopil FROM debpil")
    data = []
    for anno, debitopil in mycursor:
        if debitopil is not None:
            data.append({
                "label": str(anno),
                "value": float(debitopil)
            })
        else:
            data.append({
                "label": str(anno),
                "value": None
            })
    return jsonify(data)

if __name__ == "__main__":
    app.run(debug=True)

    
  



Gallery


Highlights of the project and some charts created in PowerBi.




Lessons Learned


During the development of "Ecochart," I learned to handle large datasets, create engaging visualizations, and implement machine learning in a web application. Since this was the final project for Generation Italy, I had the opportunity to collaborate with some of my colleagues, which significantly improved my teamwork skills. To be transparent, I primarily focused on the front-end, including the indicator charts under examination, and contributed to the back-end implementation, particularly in configuring the Flask application.




Future Plans


While I currently do not have plans for further project expansions, I am open to considering them. I remain open to evaluating possible expansions.




Links and Resources


I would like to thank all the data sources used in Ecochart and the colleagues from the Generation team for their contributions to this project.

https://www.imf.org/en/Data
http://dati.istat.it/
https://www.bancaditalia.it/statistiche/tematiche/statistiche-area-euro/