| from flask import Flask, render_template, request, redirect, url_for
|
| import pandas as pd
|
| import numpy as np
|
| import joblib
|
| import requests
|
| from keras.models import model_from_json
|
| import folium
|
| from collections import defaultdict
|
| import matplotlib
|
| matplotlib.use('Agg')
|
| import matplotlib.pyplot as plt
|
| from io import BytesIO
|
| import base64
|
| import branca
|
|
|
| app = Flask(__name__)
|
|
|
|
|
| def load_model(name):
|
| with open(f"{name}.json", "r") as json_file:
|
| loaded_model_json = json_file.read()
|
| model = model_from_json(loaded_model_json)
|
| model.load_weights(f"{name}.weights.h5")
|
| return model
|
|
|
| model = load_model("FUTURE_AQI_v1")
|
| scaler_X = joblib.load('scaler_X_cpcb_4.pkl')
|
| scaler_y = joblib.load('scaler_y_cpcb_4.pkl')
|
|
|
| API_KEY = "26daca1b78f44099a755b921be4bfcf1"
|
|
|
|
|
| @app.route('/', methods=['GET', 'POST'])
|
| def index():
|
| map_html = generate_map()
|
| if request.method == 'POST':
|
|
|
| latitude = float(request.form['latitude'])
|
| longitude = float(request.form['longitude'])
|
|
|
|
|
| current_url = f"https://api.weatherbit.io/v2.0/current/airquality?lat={latitude}&lon={longitude}&key={API_KEY}"
|
| response = requests.get(current_url)
|
| if response.status_code == 200:
|
| current_data = response.json()['data'][0]
|
|
|
|
|
| now = pd.to_datetime("now")
|
| input_data = pd.DataFrame([{
|
| 'PM2.5': current_data['pm25'],
|
| 'PM10': current_data['pm10'],
|
| 'NO2': current_data['no2'],
|
| 'SO2': current_data['so2'],
|
| 'CO': current_data['co'],
|
| 'AQI': current_data['aqi'],
|
| 'Day': now.day,
|
| 'Month': now.month,
|
| 'Hour': now.hour
|
| }])
|
|
|
|
|
| input_scaled = scaler_X.transform(input_data)
|
| predictions = model.predict(input_scaled)
|
| predictions_actual = scaler_y.inverse_transform(predictions)
|
|
|
|
|
| forecast_df = pd.DataFrame([{
|
| **input_data.iloc[0],
|
| 'lat': latitude,
|
| 'lon': longitude,
|
| 'AQI_step_1': predictions_actual[0, 0],
|
| 'AQI_step_2': predictions_actual[0, 1],
|
| 'AQI_step_3': predictions_actual[0, 2]
|
| }])
|
| forecast_df.to_csv('aqi_data.csv', mode='a', header=False, index=False)
|
|
|
|
|
| map_html = generate_map()
|
|
|
| return render_template('aqi_forecast_with_legend.html', map_html=map_html)
|
|
|
|
|
| @app.route('/forecast', methods=['POST'])
|
| def forecast():
|
|
|
| latitude = float(request.form['latitude'])
|
| longitude = float(request.form['longitude'])
|
|
|
|
|
| current_url = f"https://api.weatherbit.io/v2.0/current/airquality?lat={latitude}&lon={longitude}&key={API_KEY}"
|
| response = requests.get(current_url)
|
| if response.status_code == 200:
|
| current_data = response.json()['data'][0]
|
|
|
|
|
| now = pd.to_datetime("now")
|
| input_data = pd.DataFrame([{
|
| 'PM2.5': current_data['pm25'],
|
| 'PM10': current_data['pm10'],
|
| 'NO2': current_data['no2'],
|
| 'SO2': current_data['so2'],
|
| 'CO': current_data['co'],
|
| 'AQI': current_data['aqi'],
|
| 'Day': now.day,
|
| 'Month': now.month,
|
| 'Hour': now.hour
|
| }])
|
|
|
|
|
| input_scaled = scaler_X.transform(input_data)
|
| predictions = model.predict(input_scaled)
|
| predictions_actual = scaler_y.inverse_transform(predictions)
|
|
|
|
|
| forecast_url = f"https://api.weatherbit.io/v2.0/forecast/airquality?lat={latitude}&lon={longitude}&key={API_KEY}"
|
| response = requests.get(forecast_url)
|
| forecast_data = response.json()['data']
|
|
|
|
|
| grouped_aqi = defaultdict(list)
|
| for entry in forecast_data:
|
| date = entry['datetime'].split(':')[0]
|
| grouped_aqi[date].append(entry['aqi'])
|
|
|
|
|
| api_predictions = {date: max(values) for date, values in grouped_aqi.items()}
|
|
|
|
|
| api_df = pd.DataFrame([{
|
| 'AQI_currrent_API': current_data['aqi'],
|
| 'AQI_step_1_API': api_predictions.get(list(api_predictions.keys())[0], None),
|
| 'AQI_step_2_API': api_predictions.get(list(api_predictions.keys())[1], None),
|
| 'AQI_step_3_API': api_predictions.get(list(api_predictions.keys())[2], None)
|
| }])
|
| api_df.to_csv('aqi_data_actual_api.csv', mode='a', header=False, index=False)
|
|
|
|
|
| forecast_df = pd.DataFrame([{
|
| **input_data.iloc[0],
|
| 'lat': latitude,
|
| 'lon': longitude,
|
| 'AQI_step_1': predictions_actual[0, 0],
|
| 'AQI_step_2': predictions_actual[0, 1],
|
| 'AQI_step_3': predictions_actual[0, 2]
|
| }])
|
| forecast_df.to_csv('aqi_data.csv', mode='a', header=False, index=False)
|
|
|
|
|
| map_html = generate_map()
|
|
|
| return render_template('aqi_forecast_with_legend.html', map_html=map_html)
|
|
|
| def generate_map(output_file='templates/aqi_forecast_with_legend.html'):
|
|
|
| df1 = pd.read_csv('aqi_data.csv', on_bad_lines='skip')
|
| df2 = pd.read_csv('aqi_data_actual_api.csv', on_bad_lines='skip')
|
| data = pd.concat([df1, df2], axis=1)
|
|
|
|
|
| map_center = [data['lat'].mean(), data['lon'].mean()]
|
| m = folium.Map(location=map_center, zoom_start=10)
|
|
|
|
|
| for _, row in data.iterrows():
|
| popup_html = create_plot(row)
|
| color = get_color_for_aqi(row['AQI_step_1'])
|
| if color:
|
| folium.Marker(
|
| location=[row["lat"], row["lon"]],
|
| popup=folium.Popup(html=popup_html, max_width=500),
|
| icon=folium.Icon(color=color)
|
| ).add_to(m)
|
|
|
|
|
| map_html = m._repr_html_()
|
|
|
|
|
|
|
| return map_html
|
|
|
| def get_color_for_aqi(aqi_value):
|
| if aqi_value <= 50:
|
| return 'green'
|
| elif aqi_value <= 100:
|
| return 'lightgreen'
|
| elif aqi_value <= 150:
|
| return 'orange'
|
| elif aqi_value <= 200:
|
| return 'red'
|
| elif aqi_value <= 300:
|
| return 'purple'
|
| else:
|
| return 'gray'
|
|
|
| def create_plot(data):
|
| fig, ax = plt.subplots(figsize=(5, 2))
|
| categories = ['DAY 1', 'DAY 2', 'DAY 3']
|
| actual_values = [data['AQI_step_1'], data['AQI_step_2'], data['AQI_step_3']]
|
| api_values = [data['AQI_step_1_API'], data['AQI_step_2_API'], data['AQI_step_3_API']]
|
|
|
| bar_width = 0.35
|
| index = range(len(categories))
|
|
|
|
|
| bars_actual = ax.barh(index, actual_values, bar_width, label="Model AQI", color='blue')
|
| bars_api = ax.barh([i + bar_width for i in index], api_values, bar_width, label="API AQI", color='green')
|
|
|
|
|
| max_value = 0
|
| for bar in bars_actual:
|
| value = bar.get_width()
|
| ax.text(value + 2, bar.get_y() + bar.get_height() / 2,
|
| f'{value:.1f}', va='center', fontsize=10)
|
| max_value = max(max_value, value)
|
| for bar in bars_api:
|
| value = bar.get_width()
|
| ax.text(value + 2, bar.get_y() + bar.get_height() / 2,
|
| f'{value:.1f}', va='center', fontsize=10)
|
| max_value = max(max_value, value)
|
|
|
|
|
| ax.set_xlim(0, max_value * 1.2)
|
|
|
|
|
| ax.set_yticks([i + bar_width / 2 for i in index])
|
| ax.set_yticklabels(categories)
|
| ax.set_xlabel('AQI')
|
| ax.set_title('AQI Comparison')
|
|
|
|
|
| ax.legend(loc='center left', bbox_to_anchor=(1, 0.5), frameon=False)
|
|
|
| plt.tight_layout()
|
|
|
|
|
| buffer = BytesIO()
|
| plt.savefig(buffer, format="png", bbox_inches='tight')
|
| plt.close(fig)
|
| buffer.seek(0)
|
|
|
|
|
| image_base64 = base64.b64encode(buffer.read()).decode()
|
| return f'<img src="data:image/png;base64,{image_base64}">'
|
|
|
| if __name__ == '__main__':
|
| app.run(debug=True)
|
|
|