Kerala Landslide severity info and Rainfall trends Visualization¶
Project Description This project uses Python to create an interactive map of Kerala with rainfall trends and landslide severity as tooltips.Python Library Folium was relied upon for map creation, Matplotlib for plotting rainfall data, and GeoJSON files to overlay district boundaries. Also a toggle functionality to show or hide overlaid district layers, allowing user interactivity over the map view.
This map includes:
GeoJSON overlays of Kerala districts. Rainfall trends (Normal and Actual) displayed as graphs in popups for selected districts. Landslide severity information (High, Moderate, Low) displayed as popups for all districts.
Features
- Interactive Map: Displays Kerala with landslide prone district boundaries alone.
- Rainfall Graphs: Popups for these districts showing rainfall trends.
- Landslide Severity: Popups indicating landslide risk levels.
Installation Prerequisites
- Python 3.7 or above
Necessary Python Libraries:
- folium
- pandas
- matplotlib
Steps Followed
Step 1: Data Preparation Ensure GeoJSON files for Kerala districts (kerala_districts.geojson) and individual district data (district_name.geojson) are available in the data/ folder. Rainfall data is in CSV format with the following columns: Dates: Daily date values For Idukki, Malapuram, Trivandrum, Kottayam and Monthly date values for Wayanad. NORMAL (mm): Normal rainfall values. ACTUAL (mm): Actual rainfall values. Landslide severity data manually entered represented as severity levels: High, Moderate, Low.
Step 2: Generate Rainfall Graphs using python script.
Step 3: Generate Map
Run the script to create the map.
Step 4: View the Map
Open the map.html in web browser to explore the interactive map.
Source Code¶
# Bringing in Rainfall datasets
import pandas as pd
# Load 5 CSV datasets
df1 = pd.read_csv(r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\IdukkiRainFall.csv')
df2 = pd.read_csv(r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\KottaymRainfall.csv')
df3 = pd.read_csv(r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\MalapurmRainfall.csv')
df4 = pd.read_csv(r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\TrivandrumRain.csv')
df5 = pd.read_csv(r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\WayandRain.csv')
Graph creation for Idukki, Kottayam, Malapuram, Trivandrum and Wayanad rainfall data¶
# Import necessary libraries
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
# File path for Idukki dataset
csv_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\IdukkiRainFall.csv'
# Load the dataset, skipping the first two rows if there's metadata
df1 = pd.read_csv(csv_path, skiprows=2)
# Strip column names of any extra spaces
df1.columns = df1.columns.str.strip()
# Debug: Print initial data
print("Initial Data:")
print(df1.head())
# Convert Dates to datetime format
df1['Dates'] = pd.to_datetime(df1['Dates'], format='%d-%b-%y', errors='coerce')
# Remove rows where both NORMAL (mm) and ACTUAL (mm) are zero
df1 = df1[(df1['NORMAL (mm)'] > 0) | (df1['ACTUAL (mm)'] > 0)]
# Debug: Check filtered data
print("Filtered Data:")
print(df1.head())
# Check if data is empty
if df1.empty:
print("No valid data for plotting. Dataset is empty.")
else:
print("Data is ready for plotting.")
# Plot the rainfall trends
plt.figure(figsize=(12, 6))
# Plot NORMAL rainfall
plt.plot(df1['Dates'], df1['NORMAL (mm)'], label='Normal Rainfall (mm)', marker='o')
# Plot ACTUAL rainfall
plt.plot(df1['Dates'], df1['ACTUAL (mm)'], label='Actual Rainfall (mm)', marker='o')
# Add labels, title, and legend
plt.xlabel('Years')
plt.ylabel('Rainfall (mm)')
plt.title('Daily Rainfall Trends (Idukki, Jan 2020 - Aug 2024)')
plt.legend()
plt.grid()
# Format x-axis to show only years
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y')) # Show only year
plt.gca().xaxis.set_major_locator(mdates.YearLocator()) # Major ticks at yearly intervals
# Rotate x-axis labels for better readability
plt.xticks(rotation=45)
# Save the graph as a file
#save_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\rainfall_idukki.png'
#plt.tight_layout() # Adjust layout before saving
#plt.savefig(save_path) # Save the plot
#print(f"Graph saved at: {save_path}")
# Display the plot
plt.tight_layout()
plt.show()
# Close the plot
plt.close()
# File path for Malappuram dataset
csv_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\MalapurmRainfall.csv'
# Load the dataset, skipping the first two rows
df1 = pd.read_csv(csv_path, skiprows=2)
# Strip column names of any extra spaces
df1.columns = df1.columns.str.strip()
# Convert Dates to datetime format
df1['Dates'] = pd.to_datetime(df1['Dates'], format='%d-%b-%y', errors='coerce')
# Drop rows with invalid or missing data in 'Dates', 'NORMAL (mm)', or 'ACTUAL (mm)'
df1 = df1.dropna(subset=['Dates', 'NORMAL (mm)', 'ACTUAL (mm)'])
# Remove rows where both NORMAL (mm) and ACTUAL (mm) are zero
df1 = df1[(df1['NORMAL (mm)'] > 0) | (df1['ACTUAL (mm)'] > 0)]
# Check if there’s data to plot
if df1.empty:
print("No non-zero rainfall data found. Exiting...")
else:
# Plot the rainfall trends
plt.figure(figsize=(12, 6))
# Plot NORMAL rainfall
plt.plot(df1['Dates'], df1['NORMAL (mm)'], label='Normal Rainfall (mm)', marker='o')
# Plot ACTUAL rainfall
plt.plot(df1['Dates'], df1['ACTUAL (mm)'], label='Actual Rainfall (mm)', marker='o')
# Add labels, title, and legend
#plt.xlabel('Dates')
#plt.ylabel('Rainfall (mm)')
#plt.title('Daily Rainfall Trends (Malappuram, Jan 2020 - Aug 2024)')
#plt.legend()
#plt.grid()
# Rotate x-axis labels for better readability
plt.xticks(rotation=45)
# Save the graph as a file
#save_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\rainfall_malappuram.png'
#plt.tight_layout() # Adjust layout before saving
#plt.savefig(save_path) # Save the plot
#print(f"Graph saved at: {save_path}")
# Display the plot
plt.show()
# Close the plot
plt.close()
# File path for Wayanad dataset
csv_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\WayandRain.csv'
# Load the dataset, skipping the first two rows
df1 = pd.read_csv(csv_path, skiprows=2)
# Strip column names of any extra spaces
df1.columns = df1.columns.str.strip()
# Debug: Print initial data
print("Initial Data:")
print(df1.head())
# Convert Dates to datetime format (assuming format is %b-%y for monthly data)
df1['Dates'] = pd.to_datetime(df1['Dates'], format='%b-%y', errors='coerce')
# Debug: Check parsed dates
print("Parsed Dates:")
print(df1['Dates'].head())
# Remove rows where both NORMAL (mm) and ACTUAL (mm) are zero
df1 = df1[(df1['NORMAL (mm)'] > 0) | (df1['ACTUAL (mm)'] > 0)]
# Debug: Check filtered data
print("Filtered Data:")
print(df1.head())
# Check if data is empty
if df1.empty:
print("No valid data for plotting. Dataset is empty.")
else:
print("Data is ready for plotting.")
# Plot the rainfall trends
plt.figure(figsize=(12, 6))
# Plot NORMAL rainfall
plt.plot(df1['Dates'], df1['NORMAL (mm)'], label='Normal Rainfall (mm)', marker='o')
# Plot ACTUAL rainfall
plt.plot(df1['Dates'], df1['ACTUAL (mm)'], label='Actual Rainfall (mm)', marker='o')
# Add labels, title, and legend
plt.xlabel('Months')
plt.ylabel('Rainfall (mm)')
plt.title('Monthly Rainfall Trends (Wayanad, Jan 2020 - Aug 2024)')
plt.legend()
plt.grid()
# Rotate x-axis labels for better readability
plt.xticks(rotation=45)
# Save the graph as a file
#save_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\rainfall_wayanad.png'
#plt.tight_layout() # Adjust layout before saving
#plt.savefig(save_path) # Save the plot
#print(f"Graph saved at: {save_path}")
# Display the plot
plt.show()
# Close the plot
plt.close()
# File path for Trivandrum dataset
csv_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\TrivandrumRain.csv'
# Load the dataset, skipping the first two rows if there's metadata
df1 = pd.read_csv(csv_path, skiprows=2)
# Strip column names of any extra spaces
df1.columns = df1.columns.str.strip()
# Debug: Print initial data
print("Initial Data:")
print(df1.head())
# Correctly parse the Dates column to datetime format
df1['Dates'] = pd.to_datetime(df1['Dates'], format='%d-%b-%Y', errors='coerce')
# Debug: Check parsed dates
print("Parsed Dates:")
print(df1['Dates'].head())
# Remove rows where both NORMAL (mm) and ACTUAL (mm) are zero
df1 = df1[(df1['NORMAL (mm)'] > 0) | (df1['ACTUAL (mm)'] > 0)]
# Check for empty or filtered data
#print("Filtered Data:")
#print(df1.head())
# Check if data is empty
if df1.empty:
print("No valid data for plotting. Dataset is empty.")
else:
print("Data is ready for plotting.")
# Plot the rainfall trends
plt.figure(figsize=(12, 6))
# Plot NORMAL rainfall
plt.plot(df1['Dates'], df1['NORMAL (mm)'], label='Normal Rainfall (mm)', marker='o')
# Plot ACTUAL rainfall
plt.plot(df1['Dates'], df1['ACTUAL (mm)'], label='Actual Rainfall (mm)', marker='o')
# Add labels, title, and legend
plt.xlabel('Dates')
plt.ylabel('Rainfall (mm)')
plt.title('Daily Rainfall Trends (Trivandrum, Jun 2024)')
plt.legend()
plt.grid()
# Format x-axis to show months and days
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b %d %y')) # Show month and day
plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=5)) # Show every 5th day
# Rotate x-axis labels for better readability
plt.xticks(rotation=45)
#save_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\rainfall_trivandrum.png'
#plt.savefig(save_path)
#print(f"Graph saved at: {save_path}")
# Display the plot
plt.tight_layout()
plt.show()
# Close the plot
plt.close()
# File path for Kottayam dataset
csv_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\Rainfallcsv\KottaymRainfall.csv'
# Load the dataset, skipping metadata rows if necessary
df = pd.read_csv(csv_path, skiprows=2)
# Strip column names of any extra spaces
df.columns = df.columns.str.strip()
# Convert the Dates column to datetime format
df['Dates'] = pd.to_datetime(df['Dates'], format='%d-%b-%Y', errors='coerce')
# Remove rows where both NORMAL (mm) and ACTUAL (mm) are zero
df = df[(df['NORMAL (mm)'] > 0) | (df['ACTUAL (mm)'] > 0)]
# Debugging: Print the first few rows of cleaned data
print("Cleaned Data:")
print(df.head())
# Plot the rainfall trends
plt.figure(figsize=(12, 6))
# Plot NORMAL rainfall
plt.plot(df['Dates'], df['NORMAL (mm)'], label='Normal Rainfall (mm)', marker='o')
# Plot ACTUAL rainfall
plt.plot(df['Dates'], df['ACTUAL (mm)'], label='Actual Rainfall (mm)', marker='o')
# Add labels, title, and legend
plt.xlabel('Dates')
plt.ylabel('Rainfall (mm)')
plt.title('Daily Rainfall Trends (Kottayam)')
plt.legend()
plt.grid()
# Format x-axis to show only years
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
plt.gca().xaxis.set_major_locator(mdates.YearLocator()) # Major ticks at yearly intervals
# Rotate x-axis labels for better readability
plt.xticks(rotation=45)
# Save the plot as a PNG
#save_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\rainfall_kottayam.png'
#plt.savefig(save_path)
#print(f"Graph saved at: {save_path}")
# Adjust layout and display the plot
plt.tight_layout()
plt.show()
# Close the plot
plt.close()
Creation of map using Folium, Overlaid with Geojson files and Graphs in png fomat.¶
"""author: Ann Nibana SL
email: axs240170@utdallas.edu"""
import folium
import os
from http.server import HTTPServer, SimpleHTTPRequestHandler
import threading
# Start HTTP server for serving graph images
def start_http_server(directory, port=8000):
os.chdir(directory)
server = HTTPServer(("localhost", port), SimpleHTTPRequestHandler)
thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()
print(f"Serving images at http://localhost:{port}/")
return f"http://localhost:{port}/"
# Directory where graph PNGs are stored
image_dir = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL'
base_url = start_http_server(image_dir)
# Path to GeoJSON files
geojson_dir = 'data_overlay'
# Graphs for each district
graph_files = {
'Wayanad': f"{base_url}rainfall_wayanad.png",
'Idukki': f"{base_url}rainfall_idukki.png",
'Trivandrum': f"{base_url}rainfall_trivandrum.png",
'Malapuram': f"{base_url}rainfall_malappuram.png",
'Kottayam': f"{base_url}rainfall_kottayam.png"
}
# District details
district_details = {
'Wayanad': {'Severity': 'Very High', 'Deaths': 159},
'Idukki': {'Severity': 'High', 'Deaths': 120},
'Trivandrum': {'Severity': 'Low', 'Deaths': 38},
'Malapuram': {'Severity': 'Moderate', 'Deaths': 59},
'Kottayam': {'Severity': 'Low', 'Deaths': 29}
}
# Create map object
m = folium.Map(location=[10.850516, 76.271080], zoom_start=10)
# Global tooltip
tooltip = 'Click For More Info'
# Default Blue marker for Kerala
folium.Marker([10.1926, 76.3869], popup='<strong>Kerala State</strong>', tooltip=tooltip,
icon=folium.Icon(color='red')).add_to(m)
# Add Kerala overlay
kerala_overlay = os.path.join(geojson_dir, 'KeralaOverlay.json')
folium.GeoJson(
kerala_overlay,
name='Kerala State',
style_function=lambda x: {'fillColor': 'black', 'color': 'black', 'weight': 2, 'fillOpacity': 0.9}
).add_to(m)
# GeoJSON files for districts
geojson_files = [
('Wayanadoverlay.json', 'Wayanad'),
('Idukkioverlay.json', 'Idukki'),
('Trivandrumoverlay.json', 'Trivandrum'),
('Malapurmoverlay.json', 'Malapuram'),
('Kottayamoverlay.json', 'Kottayam')
]
# Add district overlays with details and a link to view rainfall trends
for filename, name in geojson_files:
overlay_path = os.path.join(geojson_dir, filename)
# Popup content with district details and a link to the rainfall trend
html_content = f"""
<h4>{name} District</h4>
<b>Landslide Severity:</b> {district_details[name]['Severity']}<br>
<b>Number of Deaths:</b> {district_details[name]['Deaths']}<br>
<a href="{graph_files[name]}" target="_blank" style="color:blue; text-decoration:underline;">
View Rainfall Trends
</a>
"""
popup = folium.Popup(folium.IFrame(html=html_content, width=300, height=150), max_width=300)
# Add GeoJSON with popup
folium.GeoJson(
overlay_path,
name=name,
popup=popup
).add_to(m)
# Add layer control to toggle between overlays
folium.LayerControl().add_to(m)
# Save the map
output_path = r'C:\Users\annni\Documents\Project_Fall\piemap_FALL\map_with_rainfall_trends.html'
m.save(output_path)
print(f"Map saved at: {output_path}")