import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import requests
import time
from typing import Dict, List
import logging
import json
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
import plotly.express as px
import plotly.graph_objects as go
from sklearn.metrics import mean_squared_error 

class NASAPowerAPI:
    def __init__(self):
        self.base_url = "https://power.larc.nasa.gov/api/temporal/daily/point"
        self.logger = self._setup_logger()
        
    def _setup_logger(self):
        logging.basicConfig(level=logging.INFO)
        return logging.getLogger(__name__)
    
    def fetch_solar_data(self, lat: float, lon: float, start_date: str, end_date: str) -> Dict:
        """
        Fetch solar and meteorological data from NASA POWER API
        Parameters:
        - lat, lon: location coordinates
        - start_date, end_date: in format 'YYYYMMDD'
        """
        parameters = [
            "ALLSKY_SFC_SW_DWN",  # Solar radiation
            "T2M",                 # Temperature at 2 meters
            "RH2M",               # Relative humidity at 2 meters
            "CLOUD_AMT",          # Cloud amount
            "ALLSKY_KT",          # Clearness index
            "WS2M"                # Wind speed at 2 meters
        ]
        
        params = {
            "start": start_date,
            "end": end_date,
            "latitude": lat,
            "longitude": lon,
            "community": "RE",
            "parameters": ",".join(parameters),
            "format": "JSON"
        }
        
        try:
            response = requests.get(self.base_url, params=params)
            response.raise_for_status()
            return response.json()
        except Exception as e:
            self.logger.error(f"Error fetching data: {str(e)}")
            return None

class SolarAnalyzer:
    def __init__(self):
        self.nasa_api = NASAPowerAPI()
        self.model = None
        self.scaler = StandardScaler()
        self.logger = logging.getLogger(__name__)

        # Gujarat cities with their coordinates
        self.gujarat_cities = {
            'Ahmedabad': {'lat': 23.0225, 'lon': 72.5714, 'region': 'Central'},
            'Surat': {'lat': 21.1702, 'lon': 72.8311, 'region': 'South'},
            'Vadodara': {'lat': 22.3072, 'lon': 73.1812, 'region': 'Central'},
            'Rajkot': {'lat': 22.3039, 'lon': 70.8022, 'region': 'Saurashtra'},
            'Bhavnagar': {'lat': 21.7645, 'lon': 72.1519, 'region': 'Saurashtra'},
            'Jamnagar': {'lat': 22.4707, 'lon': 70.0577, 'region': 'Saurashtra'},
            'Gandhinagar': {'lat': 23.2156, 'lon': 72.6369, 'region': 'Central'},
            'Bhuj': {'lat': 23.2419, 'lon': 69.6669, 'region': 'North'},
            'Mehsana': {'lat': 23.5880, 'lon': 72.3693, 'region': 'North'},
            'Patan': {'lat': 23.8493, 'lon': 72.1266, 'region': 'North'}
        }

    def calculate_solar_power(self, df: pd.DataFrame) -> pd.Series:
        """Calculate theoretical solar power output"""
        panel_efficiency = 0.18  # 18% efficient solar panels
        area = 1000  # m² of solar panels

        # Convert W/m²/day to kW
        power = (
            df['solar_radiation'] *   # Daily solar radiation
            (1 - df['cloud_cover'] * 0.005) *  # Cloud impact
            df['clearness_index'] *   # Atmospheric clarity
            (1 + 0.002 * (df['temperature'] - 25)) *  # Temperature effect
            panel_efficiency *
            area / 24  # Convert to hourly average
        )

        return np.maximum(0, power)

    def train_model(self, df: pd.DataFrame):
        """Train a machine learning model to predict solar power"""
        # Preprocess data
        df = df.dropna()

        # Split data into training and testing sets
        X = df[['temperature', 'humidity', 'cloud_cover', 'clearness_index', 'wind_speed']]
        y = df['solar_power']
        X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

        # Scale features
        self.scaler.fit(X_train)
        X_train = self.scaler.transform(X_train)
        X_test = self.scaler.transform(X_test)

        # Train model
        self.model = RandomForestRegressor(n_estimators=100, random_state=42)
        self.model.fit(X_train, y_train)

        # Evaluate model
        y_pred = self.model.predict(X_test)
        mse = mean_squared_error(y_test, y_pred)
        self.logger.info(f"Mean squared error: {mse}")

    def predict_solar_power(self, df: pd.DataFrame) -> pd.Series:
        """Predict solar power using the trained model"""
        # Preprocess data
        df = df.dropna()

        # Scale features
        X = df[['temperature', 'humidity', 'cloud_cover', 'clearness_index', 'wind_speed']]
        X = self.scaler.transform(X)

        # Predict solar power
        y_pred = self.model.predict(X)

        return y_pred

    def create_visualizations(self, df: pd.DataFrame):
        """Create analysis visualizations"""
        df['solar_power'] = self.calculate_solar_power(df)
        df['predicted_solar_power'] = self.predict_solar_power(df)

        # 1. Regional Comparison
        fig1 = px.box(
            df,
            x='region',
            y='predicted_solar_power',
            title='Predicted Solar Power Potential by Region in Gujarat',
            labels={'predicted_solar_power': 'Predicted Solar Power (kW)', 'region': 'Region'}
        )

        # 2. Monthly Trends
        df['month'] = df['date'].dt.month
        monthly_avg = df.groupby(['city', 'month'])['predicted_solar_power'].mean().reset_index()
        fig2 = px.line(
            monthly_avg,
            x='month',
            y='predicted_solar_power',
            color='city',
            title='Monthly Average Predicted Solar Power Generation',
            labels={
                'month': 'Month',
                'predicted_solar_power': 'Average Predicted Solar Power (kW)',
                'city': 'City'
            }
        )

        # 3. Geographic Distribution
        city_avg = df.groupby(['city', 'latitude', 'longitude', 'region'])['predicted_solar_power'].mean().reset_index()
        fig3 = px.scatter_mapbox(
            city_avg,
            lat='latitude',
            lon='longitude',
            size='predicted_solar_power',
            color='region',
            hover_name='city',
            hover_data=['predicted_solar_power'],
            title='Predicted Solar Power Potential Across Gujarat',
            mapbox_style='carto-positron',
            size_max=25
        )
        fig3.update_layout(
            mapbox=dict(
                center=dict(lat=22.5, lon=71.5),
                zoom=6
            )
        )

        # 4. Weather Impact Analysis
        fig4 = px.scatter(
            df,
            x='temperature',
            y='predicted_solar_power',
            color='clearness_index',
            title='Temperature vs Predicted Solar Power (Color: Clearness Index)',
            labels={
                'temperature': 'Temperature (°C)',
                'predicted_solar_power': 'Predicted Solar Power (kW)',
                'clearness_index': 'Clearness Index'
            }
        )

        return fig1, fig2, fig3, fig4

def main():
    # Initialize analyzer
    analyzer = SolarAnalyzer()

    # Set date range (last 365 days)
    end_date = datetime.now()
    start_date = end_date - timedelta(days=365)

    print("Fetching solar data from NASA POWER API...")
    data_list = []
    for city, info in analyzer.gujarat_cities.items():
        data = analyzer.nasa_api.fetch_solar_data(
            info['lat'],
            info['lon'],
            start_date.strftime('%Y%m%d'),
            end_date.strftime('%Y%m%d')
        )
        if data and 'properties' in data:
            daily_data = data['properties']['parameter']
            dates = pd.date_range(start=start_date, end=end_date)
            for date in dates:
                date_str = date.strftime('%Y%m%d')
                if date_str in daily_data['ALLSKY_SFC_SW_DWN']:
                    day_data = {
                        'date': date,
                        'city': city,
                        'region': info['region'],
                        'latitude': info['lat'],
                        'longitude': info['lon'],
                        'solar_radiation': daily_data['ALLSKY_SFC_SW_DWN'][date_str],
                        'temperature': daily_data['T2M'][date_str],
                        'humidity': daily_data['RH2M'][date_str],
                        'cloud_cover': daily_data['CLOUD_AMT'][date_str],
                        'clearness_index': daily_data['ALLSKY_KT'][date_str],
                        'wind_speed': daily_data['WS2M'][date_str]
                    }
                    data_list.append(day_data)

    df = pd.DataFrame(data_list)
    df['solar_power'] = analyzer.calculate_solar_power(df)

    print("Training machine learning model...")
    analyzer.train_model(df)

    print("Creating visualizations...")
    fig1, fig2, fig3, fig4 = analyzer.create_visualizations(df)

    # Display visualizations
    fig1.show()
    fig2.show()
    fig3.show()
    fig4.show()

    # Save data to CSV
    df.to_csv('gujarat_solar_data.csv', index=False)
    print("Data saved to gujarat_solar_data.csv")

if __name__ == "__main__":
    main()


Can you take a look and fix whatever is causing bad data to come in and generate plots with no sense?