Fetch historical weather data from a free API and visualise monthly temperature trends, rainfall patterns, and seasonal statistics with pandas and matplotlib.
Open-Meteo provides free historical weather data for any coordinates — no sign-up needed.
import requests
import pandas as pd
def fetch_weather(lat, lon, start='2024-01-01', end='2024-12-31'):
url = 'https://archive-api.open-meteo.com/v1/archive'
params = {
'latitude': lat,
'longitude': lon,
'start_date': start,
'end_date': end,
'daily': 'temperature_2m_max,temperature_2m_min,precipitation_sum',
'temperature_unit': 'celsius',
'timezone': 'auto',
}
r = requests.get(url, params=params, timeout=30)
data = r.json()['daily']
df = pd.DataFrame(data)
df['time'] = pd.to_datetime(df['time'])
df['temp_avg'] = (df['temperature_2m_max'] + df['temperature_2m_min']) / 2
return df
# Mumbai coordinates
df = fetch_weather(19.08, 72.88)
print(df.head())
print(f"\nFetched {len(df)} days of weather data")
Group by month to get monthly averages and total rainfall.
df['month'] = df['time'].dt.month
df['month_name']= df['time'].dt.strftime('%b')
monthly = df.groupby(['month','month_name']).agg(
avg_temp = ('temp_avg', 'mean'),
max_temp = ('temperature_2m_max', 'mean'),
min_temp = ('temperature_2m_min', 'mean'),
rainfall = ('precipitation_sum', 'sum'),
).reset_index().sort_values('month')
print(monthly[['month_name','avg_temp','rainfall']].to_string(index=False))
month_name avg_temp rainfall
Jan 22.0 0.2
Feb 23.5 0.0
Mar 26.9 0.0
Apr 29.6 1.0
May 31.1 20.4
Jun 27.3 543.4
Jul 26.0 785.6
Aug 26.0 510.8
Sep 26.8 325.0
Oct 28.2 64.3
Nov 27.2 2.5
Dec 24.0 0.5A dual-axis chart shows both temperature and rainfall on the same plot.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
fig, ax1 = plt.subplots(figsize=(11, 5))
# Temperature line
ax1.fill_between(monthly['month_name'], monthly['min_temp'], monthly['max_temp'],
alpha=0.2, color='#f59e0b', label='Temp range')
ax1.plot(monthly['month_name'], monthly['avg_temp'],
'o-', color='#f59e0b', linewidth=2.5, label='Avg temp')
ax1.set_ylabel('Temperature (degC)', color='#f59e0b')
ax1.tick_params(axis='y', labelcolor='#f59e0b')
# Rainfall bars on secondary axis
ax2 = ax1.twinx()
ax2.bar(monthly['month_name'], monthly['rainfall'],
alpha=0.4, color='#3b82f6', label='Rainfall (mm)')
ax2.set_ylabel('Rainfall (mm)', color='#3b82f6')
ax2.tick_params(axis='y', labelcolor='#3b82f6')
plt.title('Mumbai — Monthly Weather 2024')
lines, labels = ax1.get_legend_handles_labels()
bars, blabels = ax2.get_legend_handles_labels()
ax1.legend(lines + bars, labels + blabels, loc='upper left')
plt.tight_layout()
plt.savefig('weather_chart.png', dpi=120)
plt.show()
You fetched real-world data from a live API, cleaned it, aggregated it by month, and built a publication-quality dual-axis chart. This exact workflow is used in climate research, agritech, and logistics planning.
Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.