Skip to content
Snippets Groups Projects
Commit b4eb8677 authored by hamza masmoudi's avatar hamza masmoudi
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 421 additions and 0 deletions
.DS_Store 0 → 100644
File added
File added
File added
import pandas as pd
import os
# Define the file paths
gtn_report_path = 'GTN Report.xlsx'
glacier_data_dir = './glacier_data'
# Load the GTN report
gtn_data = pd.read_excel(gtn_report_path)
# Prepare a dictionary for region-to-country mapping based on GTN report
region_to_country = {
'alaska': 'US - UNITED STATES',
'scandinavia': 'SE - SWEDEN',
'new_zealand': 'NZ - NEW ZEALAND',
'antarctic_and_subantarctic': 'AQ - ANTARCTICA',
'russian_arctic': 'RU - RUSSIAN FEDERATION',
'greenland_periphery': 'GL - GREENLAND',
'iceland': 'IS - ICELAND',
'svalbard': 'NO - NORWAY',
'western_canada_us': 'CA - CANADA',
'arctic_canada_north': 'CA - CANADA',
'arctic_canada_south': 'CA - CANADA',
'south_asia_east': 'IN - INDIA',
'south_asia_west': 'PK - PAKISTAN',
'central_asia': 'KZ - KAZAKHSTAN',
'caucasus_middle_east': 'GE - GEORGIA',
'central_europe': 'DE - GERMANY',
'north_asia': 'CN - CHINA',
'low_latitudes': 'BR - BRAZIL',
'southern_andes': 'CL - CHILE'
}
# Initialize an empty list for storing region-country mapping
region_country_mapping = []
# Loop through each glacier CSV file in the directory
for file_name in os.listdir(glacier_data_dir):
if file_name.endswith('.csv'):
region_name = file_name.split('.')[0]
# Check if region exists in the predefined mapping
if region_name in region_to_country:
country = region_to_country[region_name]
region_country_mapping.append({'region': region_name, 'country': country})
# Create a DataFrame for region-country mapping
region_country_df = pd.DataFrame(region_country_mapping)
# Save the mapping to a CSV file
region_country_mapping_file = './data/region_to_country_mapping.csv'
region_country_df.to_csv(region_country_mapping_file, index=False)
print(f"Region to Country mapping saved to {region_country_mapping_file}")
# Now you can load this CSV into your project for future use
app.py 0 → 100644
import dash
from dash import dcc, html, Input, Output
def trigger_event(event):
pass
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import os
import zipfile
import numpy as np
# Load and prepare data
zip_path = "Glacier.zip"
gtn_report_path = "GTN Report.xlsx"
extract_dir = "glacier_data"
# Extract glacier zip contents
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
zip_ref.extractall(extract_dir)
# Load regional glacier CSV files and assign approximate coordinates for visualization
region_coordinates = {
'1_alaska': (64.2008, -149.4937),
'2_western_canada_us': (52.9399, -106.4509),
'3_arctic_canada_north': (75.0000, -100.0000),
'4_arctic_canada_south': (65.0000, -100.0000),
'5_greenland_periphery': (72.0000, -40.0000),
'6_iceland': (64.9631, -19.0208),
'7_svalbard': (78.0000, 16.0000),
'8_scandinavia': (60.0000, 15.0000),
'9_russian_arctic': (70.0000, 100.0000),
'10_north_asia': (60.0000, 90.0000),
'11_central_europe': (47.0000, 10.0000),
'12_caucasus_middle_east': (42.0000, 45.0000),
'13_central_asia': (43.0000, 75.0000),
'14_south_asia_west': (35.0000, 70.0000),
'15_south_asia_east': (27.0000, 85.0000),
'16_low_latitudes': (0.0000, -60.0000),
'17_southern_andes': (-40.0000, -70.0000),
'18_new_zealand': (-41.2865, 174.7762),
'19_antarctic_and_subantarctic': (-75.0000, 0.0000)
}
# Load glacier data into a combined DataFrame
glacier_data = []
region_files = [file for file in os.listdir(extract_dir) if file.endswith('.csv') and file != '0_global.csv']
for file in region_files:
region_name = file.replace('.csv', '')
df_region = pd.read_csv(os.path.join(extract_dir, file))
df_region['region'] = region_name
df_region['latitude'], df_region['longitude'] = region_coordinates.get(region_name, (0, 0))
glacier_data.append(df_region)
df_glacier_regions = pd.concat(glacier_data, ignore_index=True)
# Simulate river discharge based on glacier melt trends
def simulate_discharge(glacier_mass_loss):
max_discharge = 500 # Max discharge in cubic meters per second
normalized_loss = (glacier_mass_loss - glacier_mass_loss.min()) / (glacier_mass_loss.max() - glacier_mass_loss.min())
simulated_discharge = max_discharge * (1 - normalized_loss) + np.random.normal(0, 10, size=len(glacier_mass_loss))
return np.clip(simulated_discharge, 50, max_discharge)
# Enhance DataFrame with simulated discharge
df_glacier_regions['simulated_discharge'] = simulate_discharge(df_glacier_regions['combined_gt'])
# Initialize Dash app
app = dash.Dash(__name__)
app.title = "Glacier Melt Impact on Water Resources - Interactive Visualization"
# Layout with 3D globe map and a side chart for selected region details
app.layout = html.Div([
html.H1("🌍 Glacier Melt and Water Resources Visualization",
style={'textAlign': 'center', 'fontSize': '28px', 'marginBottom': '20px', 'color': '#2C3E50'}),
html.Div([
dcc.Graph(id='world-map-visualization', style={'height': '75vh', 'width': '65%', 'display': 'inline-block'}),
dcc.Graph(id='region-detail-chart', style={'height': '75vh', 'width': '33%', 'display': 'inline-block', 'paddingLeft': '1%'})
], style={'display': 'flex', 'justifyContent': 'center'}),
html.Div([
html.Label("⏩ Animation Speed:", style={'fontWeight': 'bold', 'fontSize': '16px'}),
dcc.Slider(
id='animation-speed',
min=50,
max=1000,
step=50,
value=300,
marks={50: 'Fast', 500: 'Medium', 1000: 'Slow'},
tooltip={"placement": "bottom", "always_visible": True}
)
], style={'width': '60%', 'margin': 'auto', 'paddingTop': '20px'})
])
# Callback to update the 3D world map for smoother panning and zooming
@app.callback(
Output('world-map-visualization', 'figure'),
[Input('animation-speed', 'value')]
)
def update_world_map(animation_speed):
min_size, max_size = 4, 15
normalized_sizes = (
(df_glacier_regions['glacier_area'] - df_glacier_regions['glacier_area'].min()) /
(df_glacier_regions['glacier_area'].max() - df_glacier_regions['glacier_area'].min())
)
bubble_sizes = normalized_sizes * (max_size - min_size) + min_size
fig = go.Figure()
fig.add_trace(go.Scattergeo(
lat=df_glacier_regions['latitude'],
lon=df_glacier_regions['longitude'],
mode='markers',
marker=dict(
size=bubble_sizes,
color=df_glacier_regions['simulated_discharge'],
colorscale='Viridis',
cmin=df_glacier_regions['simulated_discharge'].min(),
cmax=df_glacier_regions['simulated_discharge'].max(),
showscale=True,
colorbar=dict(title="Discharge (m³/s)", thickness=15, len=0.5),
line=dict(width=0.4, color='DarkSlateGrey')
),
text=df_glacier_regions.apply(lambda row: (
f"Region: {row['region']}<br>Year: {row['end_dates']}<br>Glacier Area: {row['glacier_area']:.2f} km²<Br>Discharge: {row['simulated_discharge']:.2f} m³/s"
), axis=1),
hoverinfo='text',
customdata=df_glacier_regions[['region']]
))
fig.update_geos(
projection_type="orthographic",
showland=True,
landcolor="rgb(230, 230, 230)",
showocean=True,
oceancolor="rgb(180, 210, 255)",
showcountries=True,
countrycolor="rgb(150, 150, 150)",
center=dict(lat=20, lon=0),
resolution=50,
)
fig.update_layout(
title="🌍 3D Globe - Glacier Melt and Water Resources",
margin=dict(l=0, r=0, t=40, b=0),
dragmode='pan',
geo=dict(
projection_rotation=dict(lon=0, lat=0),
projection_scale=0.9,
lataxis=dict(range=[-90, 90]),
lonaxis=dict(range=[-180, 180]),
),
font=dict(family="Arial", size=13, color="#2C3E50"),
)
return fig
# Callback to update the region detail chart when a bubble is clicked
@app.callback(
Output('region-detail-chart', 'figure'),
[Input('world-map-visualization', 'clickData')]
)
def update_region_chart(clickData):
if not clickData:
return go.Figure(layout=dict(title="Select a region to see details", font=dict(size=14)))
selected_region = clickData['points'][0]['customdata'][0]
region_data = df_glacier_regions[df_glacier_regions['region'] == selected_region].sort_values(by='end_dates')
fig = go.Figure()
fig.add_trace(go.Scatter(
x=region_data['end_dates'],
y=region_data['combined_gt'],
mode='lines+markers',
name='Glacier Mass Change (Gt)',
line=dict(color='blue')
))
fig.add_trace(go.Scatter(
x=region_data['end_dates'],
y=region_data['simulated_discharge'],
mode='lines+markers',
name='Simulated River Discharge (m³/s)',
line=dict(color='green')
))
fig.update_layout(
title=f"Glacier Mass vs Water Discharge - {selected_region.replace('_', ' ').title()}",
xaxis_title="Year",
yaxis_title="Value",
legend=dict(x=0.02, y=0.98),
margin=dict(l=30, r=20, t=40, b=40),
font=dict(family="Arial", size=12)
)
return fig
if __name__ == '__main__':
app.run_server(debug=True, port=8060)
:root {
--background-color: #f4f4f9;
--text-color: #34495e;
--button-bg: #34495e;
--button-text: #fff;
--box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
--border-radius: 12px;
}
.dark-mode {
--background-color: #2c3e50;
--text-color: #ecf0f1;
--button-bg: #e74c3c;
--button-text: #fff;
--box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
}
body {
font-family: Arial, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
margin: 0;
padding: 10px;
height: 100vh;
display: flex;
flex-direction: column;
}
h1 {
font-size: 30px;
font-weight: bold;
margin-bottom: 20px;
text-align: center;
}
#controls {
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
padding: 10px;
margin-bottom: 15px;
background-color: var(--background-color);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
}
.year-control {
display: flex;
align-items: center;
gap: 8px;
}
#year-input {
width: 70px;
padding: 5px;
border-radius: 6px;
text-align: center;
border: 1px solid #ccc;
}
#year-slider {
width: 200px;
}
button, select, input[type="number"], input[type="range"] {
padding: 6px 12px;
border-radius: 8px;
border: 1px solid #ccc;
cursor: pointer;
transition: all 0.2s ease;
}
button:hover, select:hover, input:hover {
box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
}
#container {
display: flex;
justify-content: space-between;
gap: 20px;
flex-grow: 1;
}
#map-container {
flex: 1;
max-width: 70%;
height: 80vh;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
}
#map {
width: 100%;
height: 100%;
border-radius: var(--border-radius);
}
#chart-container {
flex: 1;
max-width: 28%;
display: flex;
flex-direction: column;
gap: 20px;
height: 80vh;
}
#region-chart-1, #region-chart-2 {
width: 100%;
height: 220px;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
}
/* Legend */
#legend {
position: absolute;
bottom: 15px;
right: 10px;
background-color: rgba(255, 255, 255, 0.8);
padding: 15px;
border-radius: 8px;
box-shadow: var(--box-shadow);
font-weight: bold;
width: 220px;
}
#legend .color-gradient {
width: 100%;
height: 20px;
background: linear-gradient(to right, #003366, #33cc33, #ff3300);
border-radius: 8px;
margin-bottom: 10px;
}
#legend .legend-item {
display: flex;
justify-content: space-between;
font-size: 12px;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
start_dates,end_dates,glacier_area,region,combined_gt,combined_gt_errors,combined_mwe,combined_mwe_errors
2000.0,2001.0,704082.6956499998,global,-78.04414729402814,111.56095088251794,-0.1111786793375206,0.1583621138501352
2001.0,2002.0,701805.4987500003,global,-215.16931097001844,95.3001011576375,-0.3075164866023069,0.1350498121659405
2002.0,2003.0,699528.3018500003,global,-128.46636738674923,91.14634450070768,-0.1841997326262217,0.1289299604899674
2003.0,2004.0,697251.1049500001,global,-192.6724697716301,72.79887688516011,-0.2771630264606625,0.1028951725208123
2004.0,2005.0,694973.9080500001,global,-229.2369109878561,73.022158218317,-0.3308421919121849,0.1028436503023272
2005.0,2006.0,692696.71115,global,-315.0371756633185,74.19065798809451,-0.4561666396999292,0.1044578602427483
2006.0,2007.0,690419.51425,global,-279.8898739792978,72.77317030930298,-0.4066108567264724,0.1025138185768302
2007.0,2008.0,688142.31735,global,-323.16570882967466,71.78509732133082,-0.4710335566158922,0.1010360421851532
2008.0,2009.0,685865.12045,global,-178.6324817323364,71.86184704387401,-0.2612321087124307,0.1011209402057232
2009.0,2010.0,683587.9235500002,global,-231.2381243724868,71.29354455724742,-0.3392890923913098,0.1001020384598227
2010.0,2011.0,681310.7266500002,global,-231.1966727048064,72.2582027545506,-0.3403621001158775,0.101352981542154
2011.0,2012.0,679033.5297499998,global,-365.9472468839626,68.11267549573648,-0.540545313270877,0.0950926143458494
2012.0,2013.0,676756.3328500001,global,-188.0208512243996,67.35045471659744,-0.2786624991943321,0.0941254547446842
2013.0,2014.0,674479.1359500001,global,-304.73798136525033,66.47051377096227,-0.4531718327704068,0.0925856747213776
2014.0,2015.0,672201.9390499997,global,-149.889416279315,65.94044282966604,-0.2236536803279121,0.0920570437100916
2015.0,2016.0,669924.74215,global,-284.97423508815865,66.77259130583126,-0.4266624477275931,0.0932270670335857
2016.0,2017.0,667647.5452499996,global,-340.6076946742656,68.35959222730513,-0.5116960211749099,0.0952916518024702
2017.0,2018.0,665370.3483500001,global,-217.68675972042345,66.39070274109359,-0.3281507593734814,0.0924077513562398
2018.0,2019.0,663093.1514499999,global,-243.81282612823085,66.54077158950466,-0.3687965484035694,0.0924649491234518
2019.0,2020.0,660815.9545499999,global,-412.9645781490086,69.99144862252744,-0.6268117422048606,0.0969733224466875
2020.0,2021.0,658538.75765,global,-405.0394156368366,76.20680182507151,-0.6169085501621713,0.1065416966938755
2021.0,2022.0,656261.5607500002,global,-217.7163545547422,81.6846283807594,-0.3327506622695744,0.1151000186974428
2022.0,2023.0,653984.3638500002,global,-460.2989143829609,100.8285184125692,-0.7059556646949124,0.138700930079604
2023.0,2024.0,651707.1669499998,global,-548.025110248126,120.16099017378784,-0.8434372990227316,0.1662574332317422
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment