| Student's name | SCIPER |
|---|---|
| Amine Youssef | 324253 |
| Lia Lee | 423066 |
| Hsiangtien Kuo | 414354 |
Milestone 1 β’ Milestone 2 β’ Milestone 3
10% of the final grade
This is a preliminary milestone to let you set up goals for your final project and assess the feasibility of your ideas. Please, fill the following sections about your project.
(max. 2000 characters per section)
The datasets used in this milestone include travel, flights, and economic indicator data. Additional datasets may be added during further milestones to enrich the scope and improve analytical depth.
Visitors from European Countries to Switzerland (in hotel sector): the datasets are provided by the Federal Statistical Office (FSO), including annual and monthly data (in hotel sector) on tourist arrivals and overnight stays in Switzerland, categorized by visitorsβ country of residence and Swiss cantons
EU residentsβ tourism behavior: the datasets are provided by Eurostat, including information on tourism, trip characteristics (purpose, duration, and destination), nights spent, and tourism expenditure of EU residents
Airports
GitHub: the datasets are provided by OpenFlights, including airports, airlines, and routes data
Flights: the datasets are provided by Open Performance Data Initiative (OPDI) in collaboration with OpenSky Network (OSN), including monthly flight data (from Jan 2022 to Jan 2026) such as flight IDs, ICAO operators, departure and arrival airports, as well as first and last seen times of each flight
Purchasing Power adjusted GDP per capita: the datasets are provided by Eurostat, including GDP data (measured in purchasing power standards (PPS)) of European countries from 2015 to 2024
Millions of people travel throughout Europe each year, making tourism a significant economic and cultural activity. However, travel patterns vary widely depending on destination popularity, seasonality, transportation options, and travel spending. This project aims to visualize tourism flows, seasonal patterns, transportation options, and travel expenditures across various destinations in order to better understand how Europeans travel within Europe.
We address the following questions:
- Where do Europeans travel, and which destinations are the most popular?
- When do Europeans travel, and how do seasonal patterns differ across destinations?
- How do Europeans travel, and what transport modes shape tourism flows?
- How much do travelers spend, and how does spending relate to trip duration or destination type?
In addition to the broader European analysis, we will focus on Switzerland to investigate whether the frequency of travel to Switzerland is influenced by economic and geographic factors. We specifically investigate whether visitors to Switzerland are more likely to come from nations that are geographically closer to Switzerland or from nations with greater GDP levels.
Our motivation for this project comes from our own experience as international students currently living in Switzerland. Since we all come from different countries and are personally interested in traveling across Europe, we became curious about the larger patterns behind tourism in Europe and how Switzerland fits into these trends.
The target audience for this project includes students and young travelers planning trips in Europe, tourism organizations and policymakers interested in understanding regional travel behavior, and researchers studying mobility and tourism trends. By presenting the data through clear and interactive visualizations, our project aims to make complex tourism statistics easier to understand and more engaging for a broad audience.
Before starting the actual analysis, we had to spend some time cleaning the Eurostat tourism datasets because, in their raw form, they are not very easy to work with. The files contain several dimensions grouped into a single column, while the yearly observations are spread across many separate columns.
To make the data usable, we first split the encoded column into separate variables: the country of residence (geo) and, depending on the dataset, the destination country, accommodation type, or trip characteristic. Then, we converted the year columns into numeric values so that calculations and visualizations could be done properly. We also removed columns that were not directly useful for the analysis, such as frequency and unit indicators, and filtered missing values to avoid inconsistencies across countries and years.
Once the data was cleaned, the first thing we looked at was its general structure. A simple descriptive analysis already shows that tourism behavior is very uneven across Europe. Some countries appear repeatedly with much higher values than others, whether in terms of expenditure, number of trips, or nights spent.
All of these preprocessing steps, summary statistics, and visualizations can be found in the exploratory_data_analysis.ipynb file.
Some projects and organizations have explored and analyzed European tourism data. A previous group project, EuropeTourism, analyzed and visualized the peak and off-peak tourism seasons across European countries through monthly data analysis. In addition, the EU Transition Pathways Platform, an official website from the European Union, provided numerous analyses of European tourism trends and prospects. UN Tourism, a specialized agency of the United Nations, provides various detailed analyses of tourism, such as European Union Tourism Trends. Furthermore, The European Travel Commission publishes report focusing on key trends influencing tourism, including travel price sensitivity, tourism value, and potential risks. In addition, it evaluates travel sentiment and market performance across different source markets, and concludes with an economic outlook for the sector.
We will integrate multiple tourism and related travel datasets to analyze not only tourism patterns themselves but also factors influencing travel behavior. In addition to seasonality, we will further explore factors such as transportation modes, travel distance, and economic conditions, as well as whether proximity to Switzerland and GDP levels affect travel frequency to Switzerland.
Relevant flight visualized information can also be obtained from websites such as the OpenSky Network, which provides real-time air traffic data including aircraft position, callsign, aircraft type, altitude, and flight routes collected from ADS-B receivers worldwide. The data are visualized on an interactive thematic map where each aircraft is represented by a symbol at its current location, with colors encoding flight information, and additional details are displayed in a table for filtering and searching.
10% of the final grade
π The Milestone 2 report: Milestone 2
π The Functional project prototype: EUFLOW
80% of the final grade
π Process book: EUFlow Process book π Live site: EUFLOW π₯ Screencast: EUFlow
EUFlow is a scrollable, four-act data story about how Europeans travel inside their own continent, with a country-scale deep dive into Switzerland and a closing synthesis page. Every chart loads its data directly from static files in the repo and renders client-side in the browser. No backend, no build step.
The site is meant to be read top to bottom, page by page, in this order:
- Home (
index.html) opens the story with a one-sentence puzzle and a four-card chapter map. Each card deep-links into the corresponding chapter on the Europe page; two larger cards lead to the Switzerland deep-dive and the Findings synthesis. - Europe (
europe.html) is four chapters: Where Europe travels (5 beats including a side-by-side origin comparison), How Europe travels (4 beats on transport, stay length, and accommodation), When Europe travels (3 beats including paired country-vs-region seasonality), and How much it costs (4 beats including paired per-trip vs per-night spending). - Switzerland (
switzerland.html) is five chapters at country scale: Where in Switzerland, When Switzerland fills up, How visitors stay (with an interactive dual-handle year slider for the 2005-2025 window), How much they spend, and Why they come. - Findings (
findings.html) closes with three validated findings, the limitations we ran into, the data sources, and the team.
Every chart has hover tooltips with exact values. Year selectors, month selectors, and country pickers are placed top-right on the relevant frames.
The site is static. It does require a local HTTP server because the chart scripts use fetch to load JSON and CSV files.
Dependencies (all loaded from CDN, nothing to install for the site itself):
- D3.js 7.8.5
- TopoJSON 3
- Plotly (used only for the destination-trends line chart on the Europe page)
To regenerate the Switzerland preprocessed data:
- Python 3 (standard library only)
Run locally:
git clone https://github.com/com-480-data-visualization/EUFLOW.git
cd EUFLOW
# (optional) regenerate Switzerland preprocessed files
python3 preprocess_fso_for_switzerland.py
# serve any way you like
python3 -m http.server 8000
# or: npx http-server -p 8000
# or: npx serve
# open
open http://localhost:8000/Opening the HTML files directly from the file system (file://...) will not work because of browser CORS rules on local fetches.
.
βββ index.html home: hero + story preamble + chapter map + About
βββ europe.html the 4-chapter Europe story
βββ switzerland.html the 5-chapter Switzerland deep dive
βββ findings.html synthesis: findings + limitations + sources
βββ style.css single stylesheet, organized by feature
β
βββ scripts/
β βββ script.js navbar + animated stat counters
β βββ chart-1.js .. chart-4.js legacy Switzerland canton/distance/GDP charts
β βββ chart-europe-heatmap.js Europe nights choropleth
β βββ chart_origin_choropleth.js top origin by destination (with domestic)
β βββ chart_origin_choropleth_excl_same.js top foreign origin only
β βββ chart_accom_stacked.js continent-wide accommodation mix
β βββ chart_accom_country_map.js accommodation by country
β βββ chart_seasonality_country.js top month by country
β βββ chart_seasonality.js top month by NUTS 2 region
β βββ chart_seasonality_nights_heatmap.js intensity by region/month
β βββ chart_seasonality_top.js top destination each month
β βββ chart_expenditure_choropleth.js per-trip spending by origin
β βββ chart_expenditure_per_night.js per-night spending by origin
β βββ chart_expenditure_world.js per-night spending by destination
β βββ chart_expenditure_world_trip.js per-trip spending by destination
β βββ chart_expenditure_scope.js domestic vs intra-EU vs outside-EU
β βββ chart_expenditure_scatter.js per-night vs per-trip scatter
β βββ chart_nights_nuts_country.js NUTS 2 nights, by country focus
β βββ ch_top_month_per_canton.js Switzerland: top month per canton
β βββ ch_canton_month_heatmap.js Switzerland: canton x month
β βββ ch_top_origin_per_canton.js Switzerland: top foreign origin per canton
β βββ ch_domestic_foreign.js Switzerland: domestic vs foreign mix
β βββ ch_avg_stay.js Switzerland: average stay length per canton
β βββ ch_recovery.js Switzerland: dual-handle year-window slider
β βββ ch_inbound_per_night.js Switzerland: per-night spending to CH
β βββ ch_inbound_scatter.js Switzerland: per-trip vs per-night to CH
β
βββ data/
β βββ cleaned_arnraw.csv Eurostat tour_dem_tttr cleaned
β βββ cleaned_extotw.csv Eurostat tour_dem_extotw cleaned (CH dest rows kept)
β βββ cleaned_*.csv other Eurostat tables (ttw, tnws, tnac, tnw, ttws, nin2m)
β βββ cantons.geojson Swiss canton geometry
β βββ canton_annual_total_visitors.json FSO arrivals per canton per year (all origins)
β βββ canton_annual_total_eu_visitors.json FSO arrivals per canton per year (EU origins)
β βββ countries_distance.json km from Bern to each country capital
β βββ countries_distances_vs_visitors.json combined distance + visitors
β βββ eu_gdp_and_to_ch_df_merged.json GDP per capita + visits to CH
β βββ ppp_adj_gdp_per_capita.csv Eurostat sdg_10_10
β βββ px-x-1003020000_102_*.json FSO PXweb 5-D cube (raw input to preprocessing)
β βββ swissBOUNDARIES3D_1_5_TLM_KANTONSGEBIET.dbf Swiss Cantons geometry data (source: Federal Office of Topography swisstopo)
β βββ swissBOUNDARIES3D_1_5_TLM_KANTONSGEBIET.shp Swiss Cantons geometry data (source: Federal Office of Topography swisstopo)
β βββ swissBOUNDARIES3D_1_5_TLM_KANTONSGEBIET.shx Swiss Cantons geometry data (source: Federal Office of Topography swisstopo)
β
βββ exploitable_data/
β βββ most_popular_*.csv Eurostat tables in long/tidy format
β βββ percentage_accomad_per_year.csv
β βββ total_nights_spent*.csv
β βββ exp_ngt*.csv, exp_trp*.csv expenditure data, several scopes
β βββ nights_per_geo_per_month_per_year.csv
β βββ in_EU_exp_trp.csv, out_EU_exp_trp.csv, same_country_exp_trp.csv
β βββ ch_top_month_per_canton.json Switzerland preprocessed (top month)
β βββ ch_canton_month_intensity.json Switzerland preprocessed (canton x month grid)
β βββ ch_top_origin_per_canton.json Switzerland preprocessed (top foreign origin)
β βββ ch_canton_domestic_foreign.json Switzerland preprocessed (domestic vs foreign)
β βββ ch_canton_avg_stay.json Switzerland preprocessed (avg stay length)
β βββ ch_canton_arrivals_by_year.json Switzerland preprocessed (arrivals 2005-2025)
β βββ ch_inbound_expenditure.json Switzerland preprocessed (inbound spending)
β
βββ images/ hero backgrounds and thumbnails
βββ exploratory_data_analysis.ipynb Milestone 1 EDA + Eurostat cleaning pipeline
βββ preprocess_fso_for_switzerland.py FSO cube preprocessor (one-shot)
βββ other_files/ earlier sketches, intermediate scripts
βββ Milestone2.pdf
βββ README.md
Preprocessing steps produce the static files that the browser loads at runtime.
1. Eurostat tables β exploitable_data/*.csv
Source: Eurostat tables tour_dem_tttr, tour_dem_ttw, tour_dem_tnws, tour_dem_tnac, tour_dem_extotw, tour_dem_tnw, tour_occ_nim, tour_occ_nin2c, tour_occ_nin2m, sdg_10_10.
Cleaning is performed in exploratory_data_analysis.ipynb: dimension-encoded columns are split into separate variables (geo, c_dest, purpose, duration, accommod, etc.), wide year-columns are kept (the charts iterate over them), EU27_2020 and EA20 aggregate rows are kept where useful, missing values are normalized.
2. FSO PXweb cube β exploitable_data/ch_*.json
Source: data/px-x-1003020000_102_20260525-135233.json, a 5-dimensional JSON-stat cube with axes Jahr (Year) x Monat (Month) x Kanton (Canton) x Herkunftsland (Visitor's country of residence) x Indikator (Arrivals/Overnight stays). Roughly 1.2M cells.
The script preprocess_fso_for_switzerland.py decodes the cube and writes six compact derived files:
ch_top_month_per_canton.json........{canton: {year: peak_month}}ch_canton_month_intensity.json......{year: {canton: [m1..m12 arrivals]}}ch_top_origin_per_canton.json.......{canton: {year: top_foreign_origin}}, Swiss residents excludedch_canton_domestic_foreign.json.....{year: {canton: {domestic, foreign, total}}}ch_canton_avg_stay.json.............{year: {canton: nights/arrivals}}ch_canton_arrivals_by_year.json.....{canton: {year: arrivals}}, full 2005-2025 series
The Switzerland inbound expenditure subset (ch_inbound_expenditure.json) is extracted in a one-off step from data/cleaned_extotw.csv filtered to c_dest = CH. See the inline Python at the top of the file.
Re-run preprocessing:
python3 preprocess_fso_for_switzerland.pyThe script is idempotent and uses only the standard library.
3. Further_Analysis_Switzerland.ipynb
canton_annual_total_eu_visitors.jsoncantons.geojsoncountries_distance.jsoncountries_distances_vs_visitors.jsoneu_gdp_and_to_ch_df_merged.json
Modern Chromium, Firefox, and Safari. All chart scripts use ES2020 (optional chaining and nullish coalescing). IE and pre-2020 browsers will not work.
Team
- Amine Youssef (324253)
- Lia Lee (423066)
- Hsiangtien Kuo (414354)
Data sources
- Eurostat: tourism (
tour_dem_*,tour_occ_*), GDP (sdg_10_10) - Swiss Federal Statistical Office: PXweb cube
px-x-1003020000_102 - REST Countries API: https://restcountries.com/v3.1/all?fields=name,latlng
- GISCO: NUTS 2 geometry (2021, 20M resolution)
- world-atlas: country TopoJSON (110m resolution)
- Federal Office of Topography swisstopo: swissBOUNDARIES3D data
Visual stack
- D3.js 7.8.5
- Plotly (Europe destination-trends chart only)
- TopoJSON 3
- All via CDN, no npm install required for the site itself
Course
- COM-480 Data Visualization, EPFL, Spring 2026
- < 24h: 80% of the grade for the milestone
- < 48h: 70% of the grade for the milestone