mirror of
https://github.com/permissionlesstech/georelays.git
synced 2026-07-25 02:25:18 +00:00
Improve relay maps with proper world map backgrounds using cartopy
This commit is contained in:
@@ -32,6 +32,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install matplotlib pandas numpy folium scipy
|
pip install matplotlib pandas numpy folium scipy
|
||||||
|
# Install cartopy and its dependencies
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libproj-dev proj-bin proj-data libgeos-dev
|
||||||
|
pip install cartopy
|
||||||
|
|
||||||
- name: Generate relay maps
|
- name: Generate relay maps
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 988 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 1.1 MiB |
@@ -48,38 +48,47 @@ def create_interactive_map(df, output_path):
|
|||||||
|
|
||||||
def create_static_map(df, output_path):
|
def create_static_map(df, output_path):
|
||||||
"""
|
"""
|
||||||
Create a static PNG map showing relay locations on a simple world map.
|
Create a static PNG map showing relay locations on a proper world map.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
df: DataFrame containing relay data with Latitude and Longitude columns
|
df: DataFrame containing relay data with Latitude and Longitude columns
|
||||||
output_path: Path to save the PNG map
|
output_path: Path to save the PNG map
|
||||||
"""
|
"""
|
||||||
|
import cartopy.crs as ccrs
|
||||||
|
import cartopy.feature as cfeature
|
||||||
|
|
||||||
plt.figure(figsize=(15, 10))
|
plt.figure(figsize=(15, 10))
|
||||||
|
|
||||||
# Create a simple base map
|
# Create a map with a proper projection
|
||||||
ax = plt.axes()
|
ax = plt.axes(projection=ccrs.PlateCarree())
|
||||||
ax.set_facecolor('#DDEEFF') # Light blue background for oceans
|
|
||||||
|
|
||||||
# Draw a simple grid
|
# Add map features
|
||||||
for i in range(-180, 181, 30):
|
ax.add_feature(cfeature.LAND, facecolor='#E5E5E5')
|
||||||
plt.axvline(x=i, color='#CCCCCC', linestyle='--', alpha=0.5)
|
ax.add_feature(cfeature.OCEAN, facecolor='#DDEEFF')
|
||||||
|
ax.add_feature(cfeature.COASTLINE, linewidth=0.5, edgecolor='#999999')
|
||||||
|
ax.add_feature(cfeature.BORDERS, linewidth=0.3, edgecolor='#AAAAAA')
|
||||||
|
ax.add_feature(cfeature.LAKES, facecolor='#DDEEFF', edgecolor='#999999', linewidth=0.5)
|
||||||
|
ax.add_feature(cfeature.RIVERS, edgecolor='#99CCFF', linewidth=0.5)
|
||||||
|
|
||||||
for i in range(-90, 91, 30):
|
# Add grid
|
||||||
plt.axhline(y=i, color='#CCCCCC', linestyle='--', alpha=0.5)
|
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
|
||||||
|
linewidth=0.5, color='gray', alpha=0.5, linestyle='--')
|
||||||
|
gl.top_labels = False
|
||||||
|
gl.right_labels = False
|
||||||
|
|
||||||
# Set map limits
|
# Set map limits
|
||||||
plt.xlim(-180, 180)
|
ax.set_extent([-180, 180, -90, 90], crs=ccrs.PlateCarree())
|
||||||
plt.ylim(-90, 90)
|
|
||||||
|
|
||||||
# Plot relay locations
|
# Plot relay locations
|
||||||
plt.scatter(
|
plt.scatter(
|
||||||
df['Longitude'],
|
df['Longitude'],
|
||||||
df['Latitude'],
|
df['Latitude'],
|
||||||
alpha=0.7,
|
alpha=0.8,
|
||||||
c='blue',
|
c='blue',
|
||||||
s=30,
|
s=30,
|
||||||
edgecolor='white',
|
edgecolor='white',
|
||||||
linewidth=0.5
|
linewidth=0.5,
|
||||||
|
transform=ccrs.PlateCarree()
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add title and labels
|
# Add title and labels
|
||||||
@@ -95,19 +104,6 @@ def create_static_map(df, output_path):
|
|||||||
bbox=dict(boxstyle="round,pad=0.3", fc="white", alpha=0.8)
|
bbox=dict(boxstyle="round,pad=0.3", fc="white", alpha=0.8)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add labels for equator and prime meridian
|
|
||||||
plt.text(0, -5, "0° (Prime Meridian)", ha='center', fontsize=8, alpha=0.7)
|
|
||||||
plt.text(5, 0, "0° (Equator)", va='center', rotation=90, fontsize=8, alpha=0.7)
|
|
||||||
|
|
||||||
# Remove axes ticks but keep latitude/longitude labels at 30-degree intervals
|
|
||||||
plt.xticks([-180, -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180],
|
|
||||||
["180°W", "150°W", "120°W", "90°W", "60°W", "30°W", "0°",
|
|
||||||
"30°E", "60°E", "90°E", "120°E", "150°E", "180°E"],
|
|
||||||
fontsize=8)
|
|
||||||
plt.yticks([-90, -60, -30, 0, 30, 60, 90],
|
|
||||||
["90°S", "60°S", "30°S", "0°", "30°N", "60°N", "90°N"],
|
|
||||||
fontsize=8)
|
|
||||||
|
|
||||||
# Adjust layout and save
|
# Adjust layout and save
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
||||||
@@ -123,22 +119,29 @@ def create_heatmap(df, output_path):
|
|||||||
df: DataFrame containing relay data with Latitude and Longitude columns
|
df: DataFrame containing relay data with Latitude and Longitude columns
|
||||||
output_path: Path to save the PNG heatmap
|
output_path: Path to save the PNG heatmap
|
||||||
"""
|
"""
|
||||||
|
import cartopy.crs as ccrs
|
||||||
|
import cartopy.feature as cfeature
|
||||||
|
from scipy.ndimage import gaussian_filter
|
||||||
|
|
||||||
plt.figure(figsize=(15, 10))
|
plt.figure(figsize=(15, 10))
|
||||||
|
|
||||||
# Create a simple base map
|
# Create a map with a proper projection
|
||||||
ax = plt.axes()
|
ax = plt.axes(projection=ccrs.PlateCarree())
|
||||||
ax.set_facecolor('#DDEEFF') # Light blue background for oceans
|
|
||||||
|
|
||||||
# Draw a simple grid
|
# Add map features
|
||||||
for i in range(-180, 181, 30):
|
ax.add_feature(cfeature.LAND, facecolor='#E5E5E5')
|
||||||
plt.axvline(x=i, color='#CCCCCC', linestyle='--', alpha=0.5)
|
ax.add_feature(cfeature.OCEAN, facecolor='#DDEEFF')
|
||||||
|
ax.add_feature(cfeature.COASTLINE, linewidth=0.5, edgecolor='#999999')
|
||||||
|
ax.add_feature(cfeature.BORDERS, linewidth=0.3, edgecolor='#AAAAAA')
|
||||||
|
|
||||||
for i in range(-90, 91, 30):
|
# Add grid
|
||||||
plt.axhline(y=i, color='#CCCCCC', linestyle='--', alpha=0.5)
|
gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
|
||||||
|
linewidth=0.5, color='gray', alpha=0.5, linestyle='--')
|
||||||
|
gl.top_labels = False
|
||||||
|
gl.right_labels = False
|
||||||
|
|
||||||
# Set map limits
|
# Set map limits
|
||||||
plt.xlim(-180, 180)
|
ax.set_extent([-180, 180, -90, 90], crs=ccrs.PlateCarree())
|
||||||
plt.ylim(-90, 90)
|
|
||||||
|
|
||||||
# Create grid for heatmap
|
# Create grid for heatmap
|
||||||
x = np.linspace(-180, 180, 360)
|
x = np.linspace(-180, 180, 360)
|
||||||
@@ -155,7 +158,6 @@ def create_heatmap(df, output_path):
|
|||||||
heatmap[lat_idx, lon_idx] += 1
|
heatmap[lat_idx, lon_idx] += 1
|
||||||
|
|
||||||
# Apply Gaussian smoothing to heatmap
|
# Apply Gaussian smoothing to heatmap
|
||||||
from scipy.ndimage import gaussian_filter
|
|
||||||
heatmap = gaussian_filter(heatmap, sigma=3)
|
heatmap = gaussian_filter(heatmap, sigma=3)
|
||||||
|
|
||||||
# Create custom colormap (blue to white)
|
# Create custom colormap (blue to white)
|
||||||
@@ -163,7 +165,7 @@ def create_heatmap(df, output_path):
|
|||||||
cmap = LinearSegmentedColormap.from_list('custom_blue', colors)
|
cmap = LinearSegmentedColormap.from_list('custom_blue', colors)
|
||||||
|
|
||||||
# Plot heatmap
|
# Plot heatmap
|
||||||
plt.pcolormesh(x, y, heatmap, cmap=cmap, alpha=0.7)
|
plt.pcolormesh(x, y, heatmap, cmap=cmap, alpha=0.7, transform=ccrs.PlateCarree())
|
||||||
|
|
||||||
# Add title
|
# Add title
|
||||||
plt.title('Global Heatmap of BitChat-Compatible Nostr Relays', fontsize=16)
|
plt.title('Global Heatmap of BitChat-Compatible Nostr Relays', fontsize=16)
|
||||||
@@ -178,19 +180,6 @@ def create_heatmap(df, output_path):
|
|||||||
bbox=dict(boxstyle="round,pad=0.3", fc="white", alpha=0.8)
|
bbox=dict(boxstyle="round,pad=0.3", fc="white", alpha=0.8)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add labels for equator and prime meridian
|
|
||||||
plt.text(0, -5, "0° (Prime Meridian)", ha='center', fontsize=8, alpha=0.7)
|
|
||||||
plt.text(5, 0, "0° (Equator)", va='center', rotation=90, fontsize=8, alpha=0.7)
|
|
||||||
|
|
||||||
# Add longitude/latitude labels
|
|
||||||
plt.xticks([-180, -150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180],
|
|
||||||
["180°W", "150°W", "120°W", "90°W", "60°W", "30°W", "0°",
|
|
||||||
"30°E", "60°E", "90°E", "120°E", "150°E", "180°E"],
|
|
||||||
fontsize=8)
|
|
||||||
plt.yticks([-90, -60, -30, 0, 30, 60, 90],
|
|
||||||
["90°S", "60°S", "30°S", "0°", "30°N", "60°N", "90°N"],
|
|
||||||
fontsize=8)
|
|
||||||
|
|
||||||
# Adjust layout and save
|
# Adjust layout and save
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
plt.savefig(output_path, dpi=300, bbox_inches='tight')
|
||||||
|
|||||||
Reference in New Issue
Block a user