π¬οΈ Add interactive global wind map application
Browse files- Add main Gradio app with interactive wind visualization
- Include wind vectors showing direction and speed
- Add wind speed heatmap with color coding
- Implement adjustable resolution controls (5-20 degrees)
- Add realistic wind pattern simulation (trade winds, westerlies, polar)
- Include comprehensive documentation and setup instructions
- Add requirements.txt with all dependencies
- Create convenient run script for easy startup
- .gitignore +25 -0
- README.md +97 -2
- app.py +215 -0
- requirements.txt +5 -0
- run.sh +7 -0
.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Virtual environment
|
2 |
+
venv/
|
3 |
+
|
4 |
+
# Python cache
|
5 |
+
__pycache__/
|
6 |
+
*.pyc
|
7 |
+
*.pyo
|
8 |
+
*.pyd
|
9 |
+
.Python
|
10 |
+
|
11 |
+
# Temporary files
|
12 |
+
*.tmp
|
13 |
+
*.temp
|
14 |
+
*.html
|
15 |
+
|
16 |
+
# MacOS
|
17 |
+
.DS_Store
|
18 |
+
|
19 |
+
# IDE
|
20 |
+
.vscode/
|
21 |
+
.idea/
|
22 |
+
|
23 |
+
# Gradio temporary files
|
24 |
+
gradio_cached_examples/
|
25 |
+
flagged/
|
README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
---
|
2 |
title: Windmap
|
3 |
-
emoji:
|
4 |
colorFrom: yellow
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
@@ -10,4 +10,99 @@ pinned: false
|
|
10 |
license: gpl-3.0
|
11 |
---
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
title: Windmap
|
3 |
+
emoji: π¬οΈ
|
4 |
colorFrom: yellow
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
|
|
10 |
license: gpl-3.0
|
11 |
---
|
12 |
|
13 |
+
# π¬οΈ Global Wind Map
|
14 |
+
|
15 |
+
An interactive web application that displays global wind patterns on a map using Gradio and Folium.
|
16 |
+
|
17 |
+
## Features
|
18 |
+
|
19 |
+
- **Interactive Wind Visualization**: View global wind patterns with arrows showing direction and speed
|
20 |
+
- **Wind Speed Heatmap**: Color-coded overlay showing wind intensity across the globe
|
21 |
+
- **Adjustable Resolution**: Control the detail level of wind data (5-20 degree grid spacing)
|
22 |
+
- **Real-time Controls**: Toggle wind vectors and heatmap display
|
23 |
+
- **Responsive Design**: Clean, modern interface with interactive controls
|
24 |
+
|
25 |
+
## Wind Pattern Simulation
|
26 |
+
|
27 |
+
The application currently displays simulated wind data with realistic patterns:
|
28 |
+
|
29 |
+
- **Trade Winds**: Easterly winds near the equator (-30Β° to 30Β° latitude)
|
30 |
+
- **Westerlies**: Westerly winds in mid-latitudes (30Β° to 60Β° and -60Β° to -30Β°)
|
31 |
+
- **Polar Winds**: Variable winds in polar regions
|
32 |
+
|
33 |
+
## Quick Start
|
34 |
+
|
35 |
+
### Option 1: Using the run script
|
36 |
+
```bash
|
37 |
+
chmod +x run.sh
|
38 |
+
./run.sh
|
39 |
+
```
|
40 |
+
|
41 |
+
### Option 2: Manual setup
|
42 |
+
```bash
|
43 |
+
# Create and activate virtual environment
|
44 |
+
python3 -m venv venv
|
45 |
+
source venv/bin/activate
|
46 |
+
|
47 |
+
# Install dependencies
|
48 |
+
pip install -r requirements.txt
|
49 |
+
|
50 |
+
# Run the application
|
51 |
+
python app.py
|
52 |
+
```
|
53 |
+
|
54 |
+
## Usage
|
55 |
+
|
56 |
+
1. **Start the application** using one of the methods above
|
57 |
+
2. **Open your browser** to the provided URL (typically `http://localhost:7860`)
|
58 |
+
3. **Adjust controls** in the left panel:
|
59 |
+
- **Data Resolution**: Lower values = more detail (but slower rendering)
|
60 |
+
- **Show Wind Vectors**: Toggle wind direction arrows
|
61 |
+
- **Show Wind Speed Heatmap**: Toggle colored wind speed overlay
|
62 |
+
4. **Explore the map** by zooming and panning
|
63 |
+
5. **Click on wind arrows** to see detailed wind information
|
64 |
+
|
65 |
+
## Wind Speed Legend
|
66 |
+
|
67 |
+
- π΅ **Blue (0-3 m/s)**: Light winds
|
68 |
+
- π’ **Green (3-7 m/s)**: Moderate winds
|
69 |
+
- π **Orange (7-12 m/s)**: Strong winds
|
70 |
+
- π΄ **Red (12+ m/s)**: Very strong winds
|
71 |
+
|
72 |
+
## Dependencies
|
73 |
+
|
74 |
+
- **gradio**: Web interface framework
|
75 |
+
- **folium**: Interactive mapping library
|
76 |
+
- **numpy**: Numerical computations
|
77 |
+
- **pandas**: Data manipulation
|
78 |
+
- **requests**: HTTP requests (for future API integration)
|
79 |
+
|
80 |
+
## Future Enhancements
|
81 |
+
|
82 |
+
The current version uses simulated data for demonstration. Planned improvements include:
|
83 |
+
|
84 |
+
- **Real Weather Data**: Integration with APIs like:
|
85 |
+
- OpenWeather API
|
86 |
+
- NOAA Global Forecast System
|
87 |
+
- European Centre for Medium-Range Weather Forecasts
|
88 |
+
- **Historical Data**: View wind patterns from past dates
|
89 |
+
- **Weather Forecast**: Show predicted wind patterns
|
90 |
+
- **Additional Layers**: Temperature, pressure, precipitation
|
91 |
+
- **Export Features**: Save maps as images or data
|
92 |
+
|
93 |
+
## Configuration
|
94 |
+
|
95 |
+
For production deployment on Hugging Face Spaces, the application will automatically start when the Space is loaded.
|
96 |
+
|
97 |
+
## Development
|
98 |
+
|
99 |
+
To extend the application:
|
100 |
+
|
101 |
+
1. **Add real data sources** in the `get_wind_data()` function
|
102 |
+
2. **Customize map styling** in the `create_wind_map()` function
|
103 |
+
3. **Add new controls** in the Gradio interface section
|
104 |
+
4. **Implement additional weather layers** using Folium plugins
|
105 |
+
|
106 |
+
## License
|
107 |
+
|
108 |
+
GPL-3.0 License - see the LICENSE file for details.
|
app.py
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import folium
|
3 |
+
import requests
|
4 |
+
import numpy as np
|
5 |
+
import pandas as pd
|
6 |
+
from datetime import datetime, timedelta
|
7 |
+
import json
|
8 |
+
import tempfile
|
9 |
+
import os
|
10 |
+
|
11 |
+
def get_wind_data(lat_min=-90, lat_max=90, lon_min=-180, lon_max=180, resolution=5):
|
12 |
+
"""
|
13 |
+
Fetch wind data from OpenWeather API or use sample data for demonstration
|
14 |
+
In a real implementation, you'd want to use a proper weather API
|
15 |
+
"""
|
16 |
+
# For demo purposes, we'll generate sample wind data
|
17 |
+
# In production, you'd fetch from APIs like OpenWeather, NOAA, etc.
|
18 |
+
|
19 |
+
lats = np.arange(lat_min, lat_max + resolution, resolution)
|
20 |
+
lons = np.arange(lon_min, lon_max + resolution, resolution)
|
21 |
+
|
22 |
+
wind_data = []
|
23 |
+
for lat in lats:
|
24 |
+
for lon in lons:
|
25 |
+
# Generate sample wind data with realistic patterns
|
26 |
+
# Simulate trade winds and westerlies
|
27 |
+
if -30 <= lat <= 30: # Trade winds
|
28 |
+
u_wind = -5 + np.random.normal(0, 2) # Easterly
|
29 |
+
v_wind = np.random.normal(0, 1)
|
30 |
+
elif 30 < lat <= 60 or -60 <= lat < -30: # Westerlies
|
31 |
+
u_wind = 5 + np.random.normal(0, 3) # Westerly
|
32 |
+
v_wind = np.random.normal(0, 2)
|
33 |
+
else: # Polar regions
|
34 |
+
u_wind = np.random.normal(0, 2)
|
35 |
+
v_wind = np.random.normal(0, 2)
|
36 |
+
|
37 |
+
wind_speed = np.sqrt(u_wind**2 + v_wind**2)
|
38 |
+
wind_direction = np.degrees(np.arctan2(v_wind, u_wind)) % 360
|
39 |
+
|
40 |
+
wind_data.append({
|
41 |
+
'lat': lat,
|
42 |
+
'lon': lon,
|
43 |
+
'u_wind': u_wind,
|
44 |
+
'v_wind': v_wind,
|
45 |
+
'wind_speed': wind_speed,
|
46 |
+
'wind_direction': wind_direction
|
47 |
+
})
|
48 |
+
|
49 |
+
return pd.DataFrame(wind_data)
|
50 |
+
|
51 |
+
def create_wind_map(resolution=10, show_vectors=True, show_heatmap=True):
|
52 |
+
"""
|
53 |
+
Create an interactive wind map using Folium
|
54 |
+
"""
|
55 |
+
# Get wind data
|
56 |
+
wind_df = get_wind_data(resolution=resolution)
|
57 |
+
|
58 |
+
# Create base map
|
59 |
+
m = folium.Map(
|
60 |
+
location=[20, 0],
|
61 |
+
zoom_start=2,
|
62 |
+
tiles='OpenStreetMap'
|
63 |
+
)
|
64 |
+
|
65 |
+
# Add wind speed heatmap
|
66 |
+
if show_heatmap:
|
67 |
+
from folium.plugins import HeatMap
|
68 |
+
heat_data = [[row['lat'], row['lon'], row['wind_speed']]
|
69 |
+
for _, row in wind_df.iterrows()]
|
70 |
+
HeatMap(heat_data, radius=15, blur=10, gradient={
|
71 |
+
0.0: 'blue',
|
72 |
+
0.3: 'cyan',
|
73 |
+
0.5: 'lime',
|
74 |
+
0.7: 'yellow',
|
75 |
+
1.0: 'red'
|
76 |
+
}).add_to(m)
|
77 |
+
|
78 |
+
# Add wind vectors
|
79 |
+
if show_vectors:
|
80 |
+
for _, row in wind_df.iterrows():
|
81 |
+
if row['wind_speed'] > 1: # Only show significant winds
|
82 |
+
# Calculate arrow end point
|
83 |
+
scale = 0.5 # Adjust this to make arrows longer/shorter
|
84 |
+
end_lat = row['lat'] + (row['v_wind'] * scale)
|
85 |
+
end_lon = row['lon'] + (row['u_wind'] * scale)
|
86 |
+
|
87 |
+
# Color based on wind speed
|
88 |
+
if row['wind_speed'] < 3:
|
89 |
+
color = 'blue'
|
90 |
+
elif row['wind_speed'] < 7:
|
91 |
+
color = 'green'
|
92 |
+
elif row['wind_speed'] < 12:
|
93 |
+
color = 'orange'
|
94 |
+
else:
|
95 |
+
color = 'red'
|
96 |
+
|
97 |
+
# Add arrow
|
98 |
+
folium.PolyLine(
|
99 |
+
locations=[[row['lat'], row['lon']], [end_lat, end_lon]],
|
100 |
+
color=color,
|
101 |
+
weight=2,
|
102 |
+
opacity=0.7
|
103 |
+
).add_to(m)
|
104 |
+
|
105 |
+
# Add arrowhead (simplified)
|
106 |
+
folium.CircleMarker(
|
107 |
+
location=[end_lat, end_lon],
|
108 |
+
radius=2,
|
109 |
+
color=color,
|
110 |
+
fillColor=color,
|
111 |
+
fillOpacity=0.8,
|
112 |
+
popup=f"Wind Speed: {row['wind_speed']:.1f} m/s<br>Direction: {row['wind_direction']:.0f}Β°"
|
113 |
+
).add_to(m)
|
114 |
+
|
115 |
+
# Add legend
|
116 |
+
legend_html = '''
|
117 |
+
<div style="position: fixed;
|
118 |
+
bottom: 50px; left: 50px; width: 200px; height: 120px;
|
119 |
+
background-color: white; border:2px solid grey; z-index:9999;
|
120 |
+
font-size:14px; padding: 10px">
|
121 |
+
<h4>Wind Speed (m/s)</h4>
|
122 |
+
<p><span style="color:blue">β</span> 0-3 Light</p>
|
123 |
+
<p><span style="color:green">β</span> 3-7 Moderate</p>
|
124 |
+
<p><span style="color:orange">β</span> 7-12 Strong</p>
|
125 |
+
<p><span style="color:red">β</span> 12+ Very Strong</p>
|
126 |
+
</div>
|
127 |
+
'''
|
128 |
+
m.get_root().html.add_child(folium.Element(legend_html))
|
129 |
+
|
130 |
+
# Save map to temporary file
|
131 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.html')
|
132 |
+
m.save(temp_file.name)
|
133 |
+
return temp_file.name
|
134 |
+
|
135 |
+
def update_wind_map(resolution, show_vectors, show_heatmap):
|
136 |
+
"""
|
137 |
+
Update the wind map based on user inputs
|
138 |
+
"""
|
139 |
+
map_file = create_wind_map(resolution, show_vectors, show_heatmap)
|
140 |
+
return map_file
|
141 |
+
|
142 |
+
# Create Gradio interface
|
143 |
+
with gr.Blocks(title="Global Wind Map", theme=gr.themes.Soft()) as demo:
|
144 |
+
gr.Markdown("# π¬οΈ Global Wind Map")
|
145 |
+
gr.Markdown("Explore global wind patterns with interactive visualization")
|
146 |
+
|
147 |
+
with gr.Row():
|
148 |
+
with gr.Column(scale=1):
|
149 |
+
gr.Markdown("## Controls")
|
150 |
+
resolution = gr.Slider(
|
151 |
+
minimum=5,
|
152 |
+
maximum=20,
|
153 |
+
value=10,
|
154 |
+
step=5,
|
155 |
+
label="Data Resolution (degrees)",
|
156 |
+
info="Lower values = more detail (slower)"
|
157 |
+
)
|
158 |
+
show_vectors = gr.Checkbox(
|
159 |
+
value=True,
|
160 |
+
label="Show Wind Vectors",
|
161 |
+
info="Display wind direction arrows"
|
162 |
+
)
|
163 |
+
show_heatmap = gr.Checkbox(
|
164 |
+
value=True,
|
165 |
+
label="Show Wind Speed Heatmap",
|
166 |
+
info="Display wind speed as colored overlay"
|
167 |
+
)
|
168 |
+
|
169 |
+
update_btn = gr.Button("π Update Map", variant="primary")
|
170 |
+
|
171 |
+
gr.Markdown("""
|
172 |
+
### About the Data
|
173 |
+
This demo shows simulated wind data with realistic patterns:
|
174 |
+
- **Trade Winds**: Easterly winds near the equator
|
175 |
+
- **Westerlies**: Westerly winds in mid-latitudes
|
176 |
+
- **Polar Winds**: Variable winds in polar regions
|
177 |
+
|
178 |
+
In a production version, this would connect to real weather APIs like:
|
179 |
+
- OpenWeather API
|
180 |
+
- NOAA Global Forecast System
|
181 |
+
- European Centre for Medium-Range Weather Forecasts
|
182 |
+
""")
|
183 |
+
|
184 |
+
with gr.Column(scale=3):
|
185 |
+
map_html = gr.HTML(
|
186 |
+
value=create_wind_map(),
|
187 |
+
label="Wind Map"
|
188 |
+
)
|
189 |
+
|
190 |
+
# Update map when controls change
|
191 |
+
update_btn.click(
|
192 |
+
fn=update_wind_map,
|
193 |
+
inputs=[resolution, show_vectors, show_heatmap],
|
194 |
+
outputs=[map_html]
|
195 |
+
)
|
196 |
+
|
197 |
+
# Auto-update when sliders change
|
198 |
+
resolution.change(
|
199 |
+
fn=update_wind_map,
|
200 |
+
inputs=[resolution, show_vectors, show_heatmap],
|
201 |
+
outputs=[map_html]
|
202 |
+
)
|
203 |
+
show_vectors.change(
|
204 |
+
fn=update_wind_map,
|
205 |
+
inputs=[resolution, show_vectors, show_heatmap],
|
206 |
+
outputs=[map_html]
|
207 |
+
)
|
208 |
+
show_heatmap.change(
|
209 |
+
fn=update_wind_map,
|
210 |
+
inputs=[resolution, show_vectors, show_heatmap],
|
211 |
+
outputs=[map_html]
|
212 |
+
)
|
213 |
+
|
214 |
+
if __name__ == "__main__":
|
215 |
+
demo.launch()
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio>=4.0.0
|
2 |
+
folium>=0.14.0
|
3 |
+
numpy>=1.24.0
|
4 |
+
pandas>=2.0.0
|
5 |
+
requests>=2.31.0
|
run.sh
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/bin/bash
|
2 |
+
|
3 |
+
# Activate virtual environment
|
4 |
+
source venv/bin/activate
|
5 |
+
|
6 |
+
# Run the Gradio app
|
7 |
+
python app.py
|