Spaces:
Sleeping
Sleeping
| # Import Packages | |
| from google.cloud import bigquery | |
| import numpy as np | |
| import os | |
| import time | |
| import datetime | |
| import streamlit as st | |
| import requests | |
| import pandas as pd | |
| import xml.etree.ElementTree as ET | |
| import pyrebase | |
| # Set Page Layout | |
| st.set_page_config(page_title='Weather Data in Kenya',layout='wide') | |
| # Set Padding | |
| st.markdown('<style>div.block-container{padding-top:2.0rem}</style>',unsafe_allow_html=True) | |
| # Set Page Header | |
| title = """ | |
| <style> | |
| .header{ | |
| font-size : 2.5rem; | |
| font-family : sana-serif; | |
| } | |
| </style> | |
| <b><center class='header'>π€οΈ Open Weather Mapπ°πͺ</center></b> | |
| """ | |
| st.markdown(title,unsafe_allow_html=True) | |
| # Firebase initialization | |
| config = { | |
| 'apiKey': "AIzaSyAQHikJeQ7Sru-Gdy9K3YNjz0adnmTSvuQ", | |
| 'authDomain': "disaster-tweets-manageme-72580.firebaseapp.com", | |
| 'databaseURL': "https://disaster-tweets-manageme-72580-default-rtdb.firebaseio.com", | |
| 'projectId': "disaster-tweets-manageme-72580", | |
| 'storageBucket': "disaster-tweets-manageme-72580.appspot.com" | |
| } | |
| firebase = pyrebase.initialize_app(config) | |
| auth = firebase.auth() | |
| # Initialize user as None | |
| if 'user' not in st.session_state: | |
| st.session_state.user = None | |
| # User registration and sign-in | |
| if st.session_state.user is None: | |
| tab1, tab2 = st.tabs(['Sign In','Reset Password']) | |
| with tab1: | |
| email = st.text_input("Sign In Email") | |
| password = st.text_input("Sign In Password", type="password") | |
| if st.button("Sign In"): | |
| try: | |
| user = auth.sign_in_with_email_and_password(email, password) | |
| if user: | |
| st.session_state.user = user | |
| st.success(f"Successfully signed in with email: {email}") | |
| st.rerun() # Refresh the app to show the new section | |
| else: | |
| st.warning("Your email is not verified. Please check your email for a verification link.") | |
| except Exception as e: | |
| error_message = str(e) | |
| if "INVALID_EMAIL" in error_message: | |
| st.error("Invalid email. Please enter a valid email address.") | |
| else: | |
| st.error("Invalid password. Please check your password and try again.") | |
| with tab2: | |
| st.subheader("Password Reset") | |
| reset_email = st.text_input("Email to reset password") | |
| if st.button("Reset Password"): | |
| try: | |
| auth.send_password_reset_email(reset_email) | |
| st.success("Password reset email sent. Please check your email for instructions.") | |
| except Exception as e: | |
| st.error(f"Error: {e}") | |
| else: | |
| st.success(f"Logged in as: {st.session_state.user['email']}! π") | |
| # define tabs for easy accessibility | |
| tab1, tab2, tab3 = st.tabs(['Home','Get Data','View Data']) | |
| with tab1: | |
| header = """ | |
| <style> | |
| .subheader{ | |
| font-size: 1.5rem; | |
| font-family : sana-serif; | |
| } | |
| </style> | |
| <h3 class='subheader'><b>Welcome to Open Weather Map Data Collection Site for Counties in Kenya.</b></h3> | |
| """ | |
| st.markdown(header,unsafe_allow_html=True) | |
| st.markdown('This Streamlit app collects weather data from various locations across Kenya using the OpenWeatherMap API.') | |
| st.markdown(""" | |
| <b>Data Collection Steps;</b>\n | |
| - Fetch weather data from multiple locations in Kenya. | |
| - Append collected data to a BigQuery database for further analysis. | |
| """, unsafe_allow_html=True) | |
| # Initialize Environment Variable | |
| os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'adrianjuliusaluoch.json' | |
| # Initialize Client Variable | |
| client = bigquery.Client() | |
| # Function to extract text from XML element safely | |
| def get_xml_text(parent, tag, attrib=None): | |
| element = parent.find(tag) | |
| if element is not None: | |
| if attrib: | |
| return element.get(attrib) | |
| return element.text | |
| return None | |
| # create function to retrieve data from the api | |
| def get_weather(): | |
| def get_weather(api_key, location): | |
| base_url = "http://api.openweathermap.org/data/2.5/weather" | |
| params = { | |
| 'q': location, | |
| 'appid': api_key, | |
| 'units': 'metric', # You can use 'imperial' for Fahrenheit | |
| } | |
| try: | |
| response = requests.get(base_url, params=params) | |
| data = response.json() | |
| # Check if the request was successful | |
| if response.status_code == 200: | |
| # Extract additional features from XML | |
| xml_url = f'http://api.openweathermap.org/data/2.5/weather?q={location}&mode=xml&appid={api_key}' | |
| xml_response = requests.get(xml_url) | |
| xml_root = ET.fromstring(xml_response.content) | |
| # Create a DataFrame with the relevant weather information | |
| weather_data = { | |
| 'City': [location], | |
| 'Time_of_Data_Calculation': [pd.to_datetime(data['dt'], unit='s', utc=True)], | |
| 'Latitude': [data['coord']['lat']], | |
| 'Longitude': [data['coord']['lon']], | |
| 'Weather_ID': [data['weather'][0]['id']], | |
| 'Weather_Main': [data['weather'][0]['main']], | |
| 'Weather_Description': [data['weather'][0]['description']], | |
| 'Temperature': [data['main']['temp']], | |
| 'Feels_Like': [data['main']['feels_like']], | |
| 'Temp_Min': [data['main']['temp_min']], | |
| 'Temp_Max': [data['main']['temp_max']], | |
| 'Pressure': [data['main']['pressure']], | |
| 'Humidity': [data['main']['humidity']], | |
| 'Sea_Level': [data['main']['sea_level']] if 'sea_level' in data['main'] else None, | |
| 'Ground_Level': [data['main']['grnd_level']] if 'grnd_level' in data['main'] else None, | |
| 'Visibility': [data['visibility']], | |
| 'Wind_Speed': [data['wind']['speed']], | |
| 'Wind_Degree': [data['wind']['deg']], | |
| 'Wind_Gust': [data['wind']['gust']] if 'gust' in data['wind'] else None, | |
| 'Cloudiness': [data['clouds']['all']], | |
| 'Cloudiness_Name': [get_xml_text(xml_root, 'clouds', 'name')], | |
| 'Rain_1h': [data['rain']['1h']] if 'rain' in data and '1h' in data['rain'] else None, | |
| 'Rain_3h': [data['rain']['3h']] if 'rain' in data and '3h' in data['rain'] else None, | |
| 'Snow_1h': [data['snow']['1h']] if 'snow' in data and '1h' in data['snow'] else None, | |
| 'Snow_3h': [data['snow']['3h']] if 'snow' in data and '3h' in data['snow'] else None, | |
| 'Country_Code': [data['sys']['country']], | |
| 'Sunrise_Time': [pd.to_datetime(data['sys']['sunrise'], unit='s', utc=True)], | |
| 'Sunset_Time': [pd.to_datetime(data['sys']['sunset'], unit='s', utc=True)], | |
| 'Timezone': [data['timezone']], | |
| 'City_ID': [data['id']], | |
| 'City_Name': [data['name']] | |
| } | |
| df = pd.DataFrame(weather_data) | |
| return df | |
| else: | |
| print(f"{location} not found in the OpenWeatherMap DataBase.") | |
| return None | |
| except Exception as e: | |
| print(f"An error occurred: {str(e)}") | |
| return None | |
| if __name__ == "__main__": | |
| # Replace 'YOUR_API_KEY' with your actual OpenWeatherMap API key | |
| api_key = '30bc8c5f44c2f641d15a7f617af532c0' | |
| # List of locations (cities or counties) for which you want to get weather data | |
| locations = [ | |
| 'Baringo', 'Bomet', 'Bungoma', 'Busia', 'Mandeni, KE', 'Embu, KE', 'Garissa', 'Homa Bay', 'Isiolo', 'Kajiado', | |
| 'Kakamega', 'Kericho', 'Kiambu', 'Kilifi', 'Kerugoya', 'Kisii', 'Kisumu', 'Kitui', 'Kwale, KE', 'Nanyuki', | |
| 'Lamu', 'Machakos', 'Makueni', 'Mandera', 'Marsabit', 'Meru', 'Migori', 'Mombasa', "Murang'a", 'Nairobi', | |
| 'Nakuru', 'Nandi, KE', 'Narok', 'Nyamira', 'Oljoro Orok', 'Nyeri', 'Maralal', 'Siaya, KE', 'Taveta', | |
| 'Chogoria', 'Kitale', 'Lodwar', 'Eldoret', 'Vihiga', 'Wajir', 'Kapenguria'] | |
| # Create an empty DataFrame to store the results | |
| all_weather_data = pd.DataFrame() | |
| # Loop through the list of locations and concatenate DataFrames | |
| for location in locations: | |
| weather_data = get_weather(api_key, location) | |
| if weather_data is not None: | |
| all_weather_data = pd.concat([all_weather_data, weather_data], ignore_index=True) | |
| # Print the final DataFrame | |
| st.write(f'Data Collection Successful for all {len(all_weather_data)} Counties in Kenya.') | |
| all_weather_data.to_parquet('weather_data.gzip',compression='gzip',index=False) | |
| st.dataframe(all_weather_data) | |
| # Load data into cloud database | |
| def append_data(): | |
| dataframe = pd.read_parquet('weather_data.gzip') | |
| table_id = 'project-adrian-julius-aluoch.central_database.openweathermap' | |
| job = client.load_table_from_dataframe(dataframe,table_id) | |
| while job.state != 'DONE': | |
| time.sleep(2) | |
| job.reload() | |
| st.write(job.state) | |
| with tab2: | |
| st.markdown(""" | |
| This section allows you to retrieve weather data from various locations across Kenya using the OpenWeatherMap API.\n | |
| To get started, simply click the "Get Data" button below.\n | |
| The app will collect real-time weather data for all specified locations and export the data to Google Cloud BigQuery Database for Storage. | |
| """, unsafe_allow_html=True) | |
| # add widgets | |
| if st.button('Get Data from API'): | |
| with st.spinner('In progress....'): | |
| get_weather() | |
| append_data() | |
| st.success('Open Weather Data Successfully Exported to Google Cloud BigQuery', icon="β ") | |
| with tab3: | |
| st.markdown(""" | |
| **Data Viewing and Analysis:** | |
| Welcome to the data viewing section. Here, you can explore the collected weather data for various regions in Kenya. | |
| Click the "View Data" button below to display the collected data in a table format. You can verify the data and ensure that all necessary information has been successfully collected. | |
| Additionally, you can download the data as a CSV file for offline analysis or sharing with others. | |
| """) | |
| if st.button('View Data'): | |
| with st.spinner('In progress....'): | |
| sql = ( | |
| 'SELECT *' | |
| 'FROM `central_database.openweathermap`' | |
| ) | |
| data = client.query(sql).to_dataframe() | |
| data = data.sort_values(by='Time_of_Data_Calculation',ascending=False).copy().reset_index(drop=True) | |
| today_date = datetime.date.today() | |
| today_data = data[data['Time_of_Data_Calculation'].dt.date == today_date] | |
| num_today = len(today_data) | |
| st.dataframe(data) | |
| st.divider() | |
| st.markdown('<b><u>Open Weather Map Statistics</u></b>',unsafe_allow_html=True) | |
| st.text(f"Data Collection Began : {data['Time_of_Data_Calculation'].min()}\nLast Collection Date : {data['Time_of_Data_Calculation'].max()}\nToday's Date : {datetime.datetime.now()}") | |
| st.text(f"Time elapsed since data collection began: {np.subtract(data['Time_of_Data_Calculation'].max(),data['Time_of_Data_Calculation'].min())}") | |
| st.text(f"Total Number of Runs : {data.shape[0] / 46}") | |
| st.text(f"Number of Runs Today: {num_today / 46}") | |
| st.text(f"Rows : {data.shape[0]:,.0f}\nColumns : {data.shape[1]}\nCounties : {len(data['City'].unique())}") | |
| st.download_button(label='Download as csv',data=data.to_csv().encode('utf-8'),mime='text/csv',file_name='Open Weather Data in Kenya.csv') | |
| st.divider() | |
| if st.button("Sign Out"): | |
| st.session_state.user = None | |
| st.success("User successfully logged out") | |
| st.rerun() # Refresh the app to show the login section again | |