{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cb6f457b-af3e-4804-b083-6c204ec3274c",
   "metadata": {},
   "source": [
    "# Importar bibliotecas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33e95515-990b-4087-9ed4-9eca01c5e541",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import numpy as np \n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.dates as mdates\n",
    "import plotly.graph_objects as go\n",
    "import pvlib\n",
    "import warnings"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59f16b06-d7cb-4aa7-a165-85e50e05d6b5",
   "metadata": {},
   "source": [
    "**Nota importante: não alterar o nome de variáveis ou de colunas, para que o código mais à frente não deixe de funcionar.**\n",
    "\n",
    "Uma boa parte do código já está preparada. Deves completar onde estão os comentários `# TODO`, seguindo as indicações."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb698f8a-9fbc-4ea6-a631-8ea1c0628ce5",
   "metadata": {},
   "source": [
    "# Exercícios"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c55cb57-3f74-43b0-8359-bd2ae9771c07",
   "metadata": {},
   "source": [
    "## Parte A: Solar fotovoltaico"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5afca93-123b-4625-9c43-eef1290e6579",
   "metadata": {},
   "source": [
    "### **1.** Dados de consumo"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "463232d2-8d24-487f-97b7-279c6722d0db",
   "metadata": {},
   "source": [
    "Vai ao [balcão digital da E-Redes](https://balcaodigital.e-redes.pt/home) e faz login. Vai a \"Os meus locais\", depois \"Produção, consumos e potências\", e por fim \"Consultar histórico\". Depois de selecionar o local, vais ver um gráfico do consumo da tua casa este mês, até hoje.\n",
    "\n",
    "O objetivo aqui é conseguir um ano inteiro de dados. Preferencialmente de 2023, mas, se não tiveres dados disponíveis para o ano todo, e tiveres de outro ano, podes usar de outro ano.\n",
    "\n",
    "Seleciona um mês de cada vez e faz download com \"Exportar excel\" até conseguires um ano inteiro.\n",
    "\n",
    "Dentro da pasta onde tens o notebook, cria outra pasta com o nome \"consumos\". Coloca todos os ficheiros de dados dentro dessa pasta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b69c281a-74a2-4808-9e75-9ae814ad8fda",
   "metadata": {},
   "outputs": [],
   "source": [
    "filenames = os.listdir('consumos')\n",
    "warnings.filterwarnings(\"ignore\", category=UserWarning, module=\"openpyxl.styles.stylesheet\")\n",
    "\n",
    "for i, filename in enumerate(filenames):\n",
    "    df_month = pd.read_excel(os.path.join('consumos', filename), skiprows=8)\n",
    "    if i == 0:\n",
    "        df_cons = df_month\n",
    "    else:\n",
    "        df_cons = pd.concat([df_cons, df_month])\n",
    "        \n",
    "df_cons['Datetime'] = pd.to_datetime(df_cons['Data'] + ' ' + df_cons['Hora'], format='%Y/%m/%d %H:%M')\n",
    "df_cons = df_cons.drop(['Data', 'Hora', 'Estado'], axis=1).set_index('Datetime').rename({'Consumo registado (kW)': 'Consumo (kW)'}, axis=1)\n",
    "df_cons = df_cons[~((df_cons.index.month == 2) & (df_cons.index.day == 29))]\n",
    "df_cons.index = df_cons.index.map(lambda x: x.replace(year=2023))\n",
    "\n",
    "# a mudança de hora no outono gera duplicados. removemos fazendo a média de ambos.\n",
    "df_cons = df_cons.groupby(df_cons.index).mean()\n",
    "\n",
    "df_cons"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "668ae520-e2b5-4dfd-b7f9-1a361961da45",
   "metadata": {},
   "outputs": [],
   "source": [
    "if sorted(df_cons.index.month.unique().to_list()) != list(np.arange(1,13)):\n",
    "    print(\"Atenção: os teus dados não têm um ano inteiro.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "09881821-54fb-4b22-a98c-55af9f5581de",
   "metadata": {},
   "source": [
    "Em alternativa, se não conseguires aceder aos teus próprios dados de consumo, faz download do ficheiro de consumos disponível no Fénix, coloca-o na mesma pasta que o notebook, e descomenta o código abaixo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c3c7c65-6a0e-43a6-a88f-5db1fc391ad9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# df_cons = pd.read_csv('consumo_backup.csv')[['Total Consumption']]\n",
    "# df_cons.columns = ['Consumo (kW)']\n",
    "# df_cons.index = pd.date_range(start='2020-1-1', periods=len(df_cons), freq='15min')\n",
    "# df_cons = df_cons[~((df_cons.index.month == 2) & (df_cons.index.day == 29))]\n",
    "# df_cons.index = df_cons.index.map(lambda x: x.replace(year=2023))\n",
    "# df_cons"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d38026b-76d4-4ba4-ac73-d15f3e1c7103",
   "metadata": {},
   "source": [
    "### **2.** Utilizando o `pvlib`, cria uma dataframe de dados de geração de um sistema PV de 1 kWp, 30 graus de inclinação e orientado a sul, para a localização da casa em análise."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c2b4711-300c-46fe-8189-f7974beb342d",
   "metadata": {},
   "source": [
    "Vamos agora obter dados de geração PV para um sistema de 1 kW, usando o ``pvlib``, mais concretamente a função ``pvlib.iotools.get_pvgis_hourly``. Podes consultar a documentação desta função [aqui](https://pvlib-python.readthedocs.io/en/v0.11.2/reference/generated/pvlib.iotools.get_pvgis_hourly.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bf0e8b81-df15-4b6d-9c58-65564d2c62db",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: insere as coordenadas aproximadas da tua casa\n",
    "latitude = \n",
    "longitude = \n",
    "\n",
    "inclinacao = 30\n",
    "azimute = 180\n",
    "\n",
    "df_pvgis, _, _ = pvlib.iotools.get_pvgis_hourly(latitude, longitude,\n",
    "                                                surface_tilt=inclinacao,\n",
    "                                                surface_azimuth=azimute,\n",
    "                                                pvcalculation=True,\n",
    "                                                peakpower=1,\n",
    "                                                pvtechchoice='crystSi',\n",
    "                                                mountingplace='building',\n",
    "                                                start='2023')\n",
    "df_pvgis = df_pvgis[['P']].tz_localize(None).rename({'P': 'Geração (kW)'}, axis=1) / 1000\n",
    "df_pvgis.head(24)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2ed1fb5-422f-43ee-9f3d-52169811c333",
   "metadata": {},
   "source": [
    "A resolução destes dados é horária (e sempre aos 10 minutos de cada hora), o que não bate certo com os dados de consumo com resolução de 15 minutos. Por isso vamos interpolar os dados para alterar a sua resolução."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9c0fbf13-b65f-4b7e-ba38-c34ac73261c1",
   "metadata": {},
   "outputs": [],
   "source": [
    "new_index = pd.date_range(start=df_pvgis.index.min().floor(\"h\"), \n",
    "                          end=df_pvgis.index.max().ceil(\"h\"), \n",
    "                          freq=\"15min\")\n",
    "df_pvgis = df_pvgis.reindex(df_pvgis.index.union(new_index))\n",
    "df_pvgis = df_pvgis.interpolate(method=\"time\")\n",
    "df_pvgis = df_pvgis.reindex(new_index).bfill()\n",
    "df_pvgis"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a844eb5-6aa6-43cb-b351-a82f6eb51c2b",
   "metadata": {},
   "source": [
    "#### a) Qual a geração total deste sistema ao longo do ano?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d9322bd-7596-4856-a523-118400da8af5",
   "metadata": {},
   "outputs": [],
   "source": [
    "geracao_total = # TODO: calcula a geração total anual\n",
    "print(f\"Geração anual: {round(geracao_total)} kWh\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e87122e-18e3-4286-9254-df1b2b4e61eb",
   "metadata": {},
   "source": [
    "#### b) Apresenta um gráfico com a geração solar e o consumo de um dia à tua escolha."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8fd10ba9-88f3-4fa3-9a03-68d2433ac85a",
   "metadata": {},
   "source": [
    "Vamos juntar os dados numa só dataframe."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0db6ce41-4f09-438f-92aa-2a6255ebcb7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.concat([df_cons, df_pvgis], axis=1)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ebfe2ccf-c4a3-4839-ab57-b7d94c4f78cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "dia = # TODO: escolhe um dia e insere a data no formato \"ano-mês-dia\". Podes experimentar diferentes dias, em diferentes estações, e ver se observas padrões diferentes :)\n",
    "\n",
    "df_dia = df.loc[dia]\n",
    "\n",
    "plt.plot(df_dia['Consumo (kW)'], label='Consumo')\n",
    "plt.plot(df_dia['Geração (kW)'], label='Geração')\n",
    "\n",
    "plt.gca().xaxis.set_major_formatter(mdates.DateFormatter(\"%H:%M\"))\n",
    "\n",
    "plt.xlabel('Hora do dia')\n",
    "plt.ylabel('Potência (kW)')\n",
    "\n",
    "plt.xlim([df_dia.index.min(), df_dia.index.max()])\n",
    "plt.ylim(bottom=0)\n",
    "\n",
    "plt.grid()\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25940843-091f-4b98-bc55-b2395dc02db9",
   "metadata": {},
   "source": [
    "### **3.** Calcula o autoconsumo e a autossuficiência."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f74b8183-383b-463f-9214-77bbb8fdb34a",
   "metadata": {},
   "source": [
    "Para ser autoconsumida, a energia tem de ser consumida no mesmo período de 15 minutos em que é produzida.\n",
    "\n",
    "Se o consumo for superior à geração, então toda a geração é autoconsumida, e o resto da energia necessária para cobrir o consumo vem da rede.\n",
    "\n",
    "Se o consumo for inferior à geração, então a geração cobre a totalidade do consumo, e o excesso de geração é injetado na rede."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56befad2-2b26-4f6b-afda-bcfa1d6029f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "df['Autoconsumido (kW)'] = np.minimum(df['Consumo (kW)'], df['Geração (kW)'])\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93e82ed1-d5a7-43e7-8f40-4cfef34ba252",
   "metadata": {},
   "outputs": [],
   "source": [
    "geracao_total = df['Geração (kW)'].sum() * 15/60\n",
    "consumo_total = # TODO: calcula o consumo total anual\n",
    "autoconsumido_total = # TODO: calcula a energia autoconsumida total anual\n",
    "\n",
    "print(f\"Geração total: {round(geracao_total)} kWh\")\n",
    "print(f\"Consumo total: {round(consumo_total)} kWh\")\n",
    "print(f\"Total de geração autoconsumida: {round(autoconsumido_total)} kWh\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "feaaabbb-1196-46b2-a335-e0398a8e3718",
   "metadata": {},
   "outputs": [],
   "source": [
    "autoconsumo = # TODO: calcula o autoconsumo\n",
    "print(f\"Autoconsumo: {round(autoconsumo)} %\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6a1467fd-f045-4feb-ad89-db10080b00ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "autosuficiencia = # TODO: calcula a autossuficiência\n",
    "print(f\"Autossuficiência: {round(autosuficiencia)} %\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70442b23-d69c-4c7c-8e33-b6c91df18842",
   "metadata": {},
   "source": [
    "### **4.** Apresenta um gráfico comparando os perfis médios de consumo e de geração. Quais costumam ser as horas de maior consumo? Concidem com as horas de maior geração? Quais são as implicações disto?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8216335d-b01b-4369-8f7a-2ffc04749337",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create \"Time of Day\" column as hours (convert time object to a number)\n",
    "df['hour_decimal'] = df.index.hour + df.index.minute / 60  # e.g., 14:30 → 14.5\n",
    "\n",
    "# Group by the 15-minute average daily profile\n",
    "avg_load_profile = df.groupby('hour_decimal')['Consumo (kW)'].mean()\n",
    "avg_pv_profile = df.groupby('hour_decimal')['Geração (kW)'].mean()\n",
    "\n",
    "df = df.drop('hour_decimal', axis=1)\n",
    "\n",
    "# Plot\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(avg_load_profile.index, avg_load_profile, label='Perfil de consumo médio', linewidth=2)\n",
    "plt.plot(avg_pv_profile.index, avg_pv_profile, label='Perfil de geração PV médio', linewidth=2)\n",
    "\n",
    "plt.xlim([avg_load_profile.index.min(), avg_load_profile.index.max()])\n",
    "plt.ylim(bottom=0)\n",
    "\n",
    "# Formatting\n",
    "plt.xlabel('Hora do dia')\n",
    "plt.ylabel('Potência (kW)')\n",
    "plt.title('Comparação de perfis médios')\n",
    "plt.xticks(range(0, 25, 2))  # Show every 2 hours\n",
    "plt.legend()\n",
    "plt.grid()\n",
    "\n",
    "# Show plot\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ecc2248-388e-4f50-a24c-695f96fa8867",
   "metadata": {},
   "source": [
    "### **5.** Assumindo um tarifa fixa de eletricidade de 0.18€/kWh, quais as poupanças anuais na fatura da eletricidade que resultam do sistema fotovoltaico?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "02280eb5-c6cd-4f40-a102-9e3adf74ec3c",
   "metadata": {},
   "outputs": [],
   "source": [
    "tarifa = 0.18\n",
    "\n",
    "poupanca = # TODO: calcula a poupança anual\n",
    "\n",
    "print(f\"Poupança anual: {round(poupanca, 2)} €\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4cb2a3ce-9c90-4f79-8034-7734485f28cc",
   "metadata": {},
   "source": [
    "### **6.** Testa o impacto de sistemas fotovoltaicos com diferentes configurações (potência, inclinação e azimute) no perfil médio de geração, e em como este se alinha com o teu perfil de consumo médio."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95f83e61-e625-413c-9578-c5ffbb1cc07e",
   "metadata": {},
   "source": [
    "Até agora, fizemos contas com um sistema de 1 kWp horizontal. Vamos experimentar diferentes inclinações e potências instaladas.\n",
    "\n",
    "Começamos por criar uma função que repete todas as contas que fizemos anteriormente, aceitando como argumento as coordenadas do local, a inclinação, azimute, e potência instalada do sistema fotovoltaico, e a dataframe do consumo. Devolve a geração total, o autoconsumo e a autossuficiência calculadas, bem como o perfil médio diário de geração."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8973ce97-82b9-43c0-b7ef-f3cf1fd45b37",
   "metadata": {},
   "outputs": [],
   "source": [
    "def calcular_autoconsumo_e_autosuficiencia(latitude, longitude, inclinacao, azimute, potencia, df_cons):\n",
    "    df_pvgis, _, _ = pvlib.iotools.get_pvgis_hourly(latitude, longitude,\n",
    "                                                    surface_tilt=inclinacao,\n",
    "                                                    surface_azimuth=azimute,\n",
    "                                                    pvcalculation=True,\n",
    "                                                    peakpower=potencia,\n",
    "                                                    pvtechchoice='crystSi',\n",
    "                                                    mountingplace='building',\n",
    "                                                    start='2023')\n",
    "    \n",
    "    df_pvgis = df_pvgis[['P']].tz_localize(None).rename({'P': 'Geração (kW)'}, axis=1) / 1000\n",
    "    \n",
    "    new_index = pd.date_range(start=df_pvgis.index.min().floor(\"h\"), \n",
    "                              end=df_pvgis.index.max().ceil(\"h\"), \n",
    "                              freq=\"15min\")\n",
    "    df_pvgis = df_pvgis.reindex(df_pvgis.index.union(new_index))\n",
    "    df_pvgis = df_pvgis.interpolate(method=\"time\")\n",
    "    df_pvgis = df_pvgis.reindex(new_index).bfill()\n",
    "    \n",
    "    df = pd.concat([df_cons, df_pvgis], axis=1)\n",
    "\n",
    "    df['Autoconsumido (kW)'] = np.minimum(df['Consumo (kW)'], df['Geração (kW)'])\n",
    "    geracao_total = df['Geração (kW)'].sum() * 15/60\n",
    "    consumo_total = df['Consumo (kW)'].sum() * 15/60\n",
    "    autoconsumido_total = df['Autoconsumido (kW)'].sum() * 15/60\n",
    "    \n",
    "    autoconsumo = autoconsumido_total / geracao_total * 100\n",
    "    autosuficiencia = autoconsumido_total / consumo_total * 100\n",
    "\n",
    "    # Compute the average daily profile\n",
    "    df['Hora do Dia'] = df.index.hour + df.index.minute / 60\n",
    "    perfil_diario = df.groupby('Hora do Dia')[['Geração (kW)']].mean().reset_index()\n",
    "\n",
    "    return geracao_total, autoconsumo, autosuficiencia, perfil_diario"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8953cca4-8d6f-4bc9-b876-56e0c07e16e6",
   "metadata": {},
   "source": [
    "Os valores a testar para cada variável estão definidos na célula abaixo:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ddc7816a-cd73-42a8-86c3-144510e21698",
   "metadata": {},
   "outputs": [],
   "source": [
    "inclinacoes = [0, 30, 55]\n",
    "azimutes = [90, 180, 270]\n",
    "potencias = [0.25, 0.5, 1, 2, 5, 10]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82a38a4f-db55-4167-97f9-058cd24ab213",
   "metadata": {},
   "source": [
    "A célula seguinte recebe os dados do PVGIS e faz os cálculos para cada uma das combinações. É normal que demore alguns minutos a correr."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d6fea24c-029c-42b9-9a61-aa92aa8d0fdc",
   "metadata": {},
   "outputs": [],
   "source": [
    "rows = []\n",
    "daily_profiles = []  # Store profiles separately\n",
    "\n",
    "for inclinacao in inclinacoes:\n",
    "    for azimute in azimutes:\n",
    "        for potencia in potencias:\n",
    "            geracao_total, autoconsumo, autosuficiencia, daily_profile = calcular_autoconsumo_e_autosuficiencia(latitude, longitude, inclinacao, azimute, potencia, df_cons)\n",
    "            \n",
    "            # Store summary results\n",
    "            rows.append({\n",
    "                'Inclinação': inclinacao,\n",
    "                'Azimute': azimute,\n",
    "                'Potência': potencia,\n",
    "                'Autoconsumo': autoconsumo,\n",
    "                'Autossuficiência': autosuficiencia,\n",
    "                'Geração total': geracao_total\n",
    "            })\n",
    "\n",
    "            # Store daily profile with scenario identifiers\n",
    "            daily_profile['Inclinação'] = inclinacao\n",
    "            daily_profile['Azimute'] = azimute\n",
    "            daily_profile['Potência'] = potencia\n",
    "            daily_profiles.append(daily_profile)\n",
    "\n",
    "# Convert results to DataFrames\n",
    "df_results = pd.DataFrame(rows)\n",
    "df_daily_profiles = pd.concat(daily_profiles, ignore_index=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e146a77a-1b09-409e-876f-be6f1fd36db2",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "df_results"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46e35c30-df51-4974-b150-2a18411e5794",
   "metadata": {},
   "source": [
    "Vamos observar a variação do perfil de geração com a inclinação e azimute. Para isto, vamos fixar a potência. Podes ajustar este valor ao que te parecer mais adequado para o teu caso."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94d2d9a8-f776-4065-9dac-f305aff34b09",
   "metadata": {},
   "outputs": [],
   "source": [
    "potencia = 1"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9a3cf63-fbd6-4e63-ad98-9db7217fb2a6",
   "metadata": {},
   "source": [
    "O gráfico produzido pela célula seguinte é interativo. Usando os menus drop-down, \n",
    "\n",
    "**a)** Fixa o azimute nos 180º. Como varia a geração com a variação da inclinação?\n",
    "\n",
    "**b)** Fixa a inclinação nos 30º. O que observas relativamente ao impacto do azimute? Qual te parece ser o melhor azimute para o teu caso? Em que situações seriam melhores outros?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a1c6b36-438c-4139-889d-cbd0f565239e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Filter dataset to only include Potência = 1 kW\n",
    "df_filtered = df_daily_profiles[df_daily_profiles['Potência'] == potencia]\n",
    "\n",
    "# Unique values for dropdowns\n",
    "inclinacoes = df_filtered['Inclinação'].unique()\n",
    "azimutes = df_filtered['Azimute'].unique()\n",
    "\n",
    "# Store traces for different scenarios\n",
    "traces = []\n",
    "\n",
    "# PV Generation traces for different scenarios\n",
    "for (inclinacao, azimute), group in df_filtered.groupby(['Inclinação', 'Azimute']):\n",
    "    traces.append(go.Scatter(\n",
    "        x=group['Hora do Dia'], \n",
    "        y=group['Geração (kW)'], \n",
    "        mode='lines',\n",
    "        name=f\"Geração - Inclinação {inclinacao}°, Azimute {azimute}°\",\n",
    "        legendgroup=f\"{inclinacao}-{azimute}\",\n",
    "        visible=True  # Start with all traces visible\n",
    "    ))\n",
    "\n",
    "# Load Consumption trace (same for all scenarios, always visible)\n",
    "load_profile_trace = go.Scatter(\n",
    "    x=avg_load_profile.index, \n",
    "    y=avg_load_profile.values, \n",
    "    mode='lines',\n",
    "    name=\"Consumo Médio\",\n",
    "    line=dict(dash='dash', color='black'),  # Dashed black line for consumption\n",
    "    legendgroup=\"Consumo (kW)\"\n",
    ")\n",
    "traces.append(load_profile_trace)  # Append at the end\n",
    "\n",
    "# Add traces to figure\n",
    "fig = go.Figure(data=traces)\n",
    "\n",
    "# Function to generate dropdown options\n",
    "def generate_dropdown_options(values, column_name):\n",
    "    options = [{'label': \"All\", 'method': \"update\", \n",
    "                'args': [{\"visible\": [True] * (len(traces) - 1) + [True]}]}]  # Always keep the last trace (load profile) visible\n",
    "    \n",
    "    for value in values:\n",
    "        visibility = [\n",
    "            (trace.legendgroup.startswith(f\"{value}-\") if column_name == \"Inclinação\" else\n",
    "             trace.legendgroup.split('-')[1] == str(value) if trace.legendgroup != \"Consumo\" else True)\n",
    "            for trace in traces[:-1]  # Exclude the last trace (load profile) from filtering\n",
    "        ]\n",
    "        visibility.append(True)  # Ensure load profile stays visible\n",
    "        options.append({'label': f\"{column_name} {value}\", 'method': \"update\", 'args': [{\"visible\": visibility}]})\n",
    "    \n",
    "    return options\n",
    "\n",
    "# Add dropdown menus\n",
    "fig.update_layout(\n",
    "    updatemenus=[\n",
    "        dict(\n",
    "            buttons=generate_dropdown_options(inclinacoes, \"Inclinação\"),\n",
    "            direction=\"down\", \n",
    "            x=0.15, xanchor=\"center\", \n",
    "            y=1.05, yanchor=\"top\"\n",
    "        ),\n",
    "        dict(\n",
    "            buttons=generate_dropdown_options(azimutes, \"Azimute\"),\n",
    "            direction=\"down\", \n",
    "            x=0.35, xanchor=\"center\", \n",
    "            y=1.05, yanchor=\"top\"\n",
    "        )\n",
    "    ],\n",
    "    title=\"Comparação de Perfis Diários de Geração PV vs. Consumo (1 kW)\",\n",
    "    title_x=0.5,  # Center the title\n",
    "    xaxis_title=\"Hora do Dia\",\n",
    "    yaxis_title=\"Energia (kW)\",\n",
    "    template=\"plotly_white\",\n",
    "    width=1200,\n",
    "    height=700,\n",
    "    \n",
    "    # Set x-axis ticks every 3 units (based on your data)\n",
    "    xaxis=dict(\n",
    "        tickmode='array',\n",
    "        tickvals=[i for i in range(0, len(df_filtered), 3)],  # Every 3rd unit\n",
    "        ticktext=[f\"{i}\" for i in range(0, len(df_filtered), 3)]  # Adjust labels accordingly\n",
    "    )\n",
    ")\n",
    "\n",
    "fig.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "922d61d4-7a5b-42cc-ba97-65f0a72995dd",
   "metadata": {},
   "source": [
    "### **7.** Como variam o autoconsumo e autossuficiência com a variação da potência instalada do sistema fotovoltaico?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e317c864-771d-4719-bdb5-144926f3a7b1",
   "metadata": {},
   "source": [
    "Observa o gráfico seguinte. Como varia o autoconsumo com o aumento da potência instalada?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f580966-cff4-48ea-8d8a-7dfe18197730",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.scatter(df_results[\"Potência\"], df_results[\"Autoconsumo\"], alpha=0.7)\n",
    "\n",
    "plt.xlabel(\"Potência (kW)\")\n",
    "plt.ylabel(\"Autoconsumo (%)\")\n",
    "\n",
    "plt.xlim(left=0)\n",
    "\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4630ef15-e466-44ca-b0a2-f6432d4f2f58",
   "metadata": {},
   "source": [
    "Reproduz o gráfico anterior, desta vez para a autossuficiência. Como varia?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "71c887a5-d014-4a5d-8487-1142649c5739",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: gráfico da autossuficiência em função da potência instalada"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1b48ecd-fd10-44af-98f9-aeb362b06f9e",
   "metadata": {},
   "source": [
    "### **8.** O que poderias fazer, a nível de comportamentos/consumos, para aumentar o teu autoconsumo e autossuficiência?"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b71dfb6-477a-4524-8d09-4e127af1497a",
   "metadata": {},
   "source": [
    "## Parte B: Solar térmico"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7bc4b47-7480-46de-9f99-d0e9fbedf9d7",
   "metadata": {},
   "source": [
    "### **1.** Calcula:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0877ab32-7918-4778-a64f-d25393425fb3",
   "metadata": {},
   "source": [
    "#### a) a energia útil necessária para que 40 l de água a 15ºC atinjam uma temperatura de 50ºC."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "908957a9-ad57-4f0b-8869-784d8aecb513",
   "metadata": {},
   "outputs": [],
   "source": [
    "E = # TODO: calcular a energia útil\n",
    "\n",
    "print(f\"Energia útil: {round(E)} J\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2ce3724-29a2-4684-aeba-219cdb511986",
   "metadata": {},
   "source": [
    "#### b) o rendimento de um coletor plano com parâmetros característicos $\\eta_0 = 0.8$, $\\alpha_1 = 7$, e $\\alpha_2 = 0.014$ para as temperaturas da alínea anterior, e uma irradiância média de $G = 1000$ W/m$^2$. Qual dos dois tem maior impacto: as perdas óticas, ou as perdas térmicas?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f9ec985d-6398-4252-862e-43f1015f8760",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: calcular\n",
    "\n",
    "perdas_oticas = \n",
    "perdas_termicas = \n",
    "\n",
    "eficiencia = \n",
    "\n",
    "print(f\"Perdas óticas: {round(perdas_oticas, 3)}\")\n",
    "print(f\"Perdas térmicas: {round(perdas_termicas, 3)}\")\n",
    "print(f\"Eficiência: {round(eficiencia, 3)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41c38b5d-ef05-4b3b-b122-9d3054b56979",
   "metadata": {},
   "source": [
    "### **2.** Calcula, para cada dia do ano, a energia diária fornecida por um coletor plano de 1 m2, em posição horizontal, com os parâmetros da questão anterior. Para fins de cálculo da eficiência, assume uma irradiância média de 700 W/m2."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc9d0873-9245-4058-bd80-3fdcb58c681f",
   "metadata": {},
   "source": [
    "Começamos por receber dados do PVGIS para a localização da casa em análise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ea20eaf2-a521-4163-b205-7637e523dcbe",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_, _, _ = pvlib.iotools.get_pvgis_hourly(latitude, longitude, start=2023, end=2023)\n",
    "df_['poa_total'] = df_['poa_direct'] + df_['poa_sky_diffuse']\n",
    "df_"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce6910a8-7591-4d98-a9b7-c62bad6b7979",
   "metadata": {},
   "source": [
    "Vamos agregar os dados por dia, calculando a soma no caso da radiação, e a média no caso da temperatura."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "df2e6465-c9a7-49d8-a751-68feeca66d1c",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_diaria = df_.resample('D').agg({'poa_total': 'sum',\n",
    "                                   'temp_air': 'mean'})\n",
    "\n",
    "df_diaria['poa_total'] = df_diaria['poa_total']/1000\n",
    "\n",
    "df_diaria = df_diaria.rename(columns={'poa_total': 'Irradiação (kWh/m2)', \n",
    "                                    'temp_air': 'Temperatura (ºC)'})\n",
    "\n",
    "df_diaria.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "405c3ee6-b273-49bc-8dd1-2c00daf7b7e6",
   "metadata": {},
   "outputs": [],
   "source": [
    "fig, ax1 = plt.subplots(figsize=(10, 6))\n",
    "\n",
    "# Plot Total Irradiation on the first y-axis (left)\n",
    "ax1.set_xlabel(\"Dia\")\n",
    "ax1.set_ylabel(\"Irradiação (kWh/m2)\", color=\"tab:orange\")\n",
    "ax1.plot(df_diaria.index, df_diaria[\"Irradiação (kWh/m2)\"], color=\"tab:orange\", label=\"Irradiação (kWh/m2)\")\n",
    "ax1.tick_params(axis=\"y\", labelcolor=\"tab:orange\")\n",
    "ax1.grid(True, which='both', linestyle='--', linewidth=0.5)\n",
    "\n",
    "# Create a second y-axis (right) for Temperature\n",
    "ax2 = ax1.twinx()\n",
    "ax2.set_ylabel(\"Temperatura Média (°C)\", color=\"tab:blue\")\n",
    "ax2.plot(df_diaria.index, df_diaria[\"Temperatura (ºC)\"], color=\"tab:blue\", label=\"Temperatura Média (°C)\")\n",
    "ax2.tick_params(axis=\"y\", labelcolor=\"tab:blue\")\n",
    "\n",
    "plt.xlim([df_pvgis.index.min(), df_pvgis.index.max()])\n",
    "\n",
    "ax1.xaxis.set_major_locator(mdates.MonthLocator())  # Monthly ticks\n",
    "ax1.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))  # Format: \"Jan 01\", \"Feb 01\", etc.\n",
    "\n",
    "# Rotate x-tick labels for better readability\n",
    "for label in ax1.get_xticklabels():\n",
    "    label.set_rotation(90)\n",
    "    label.set_ha(\"right\")\n",
    "    \n",
    "# Show the plot\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "695bd352-cf64-40bb-b1c0-59a3f31305c9",
   "metadata": {},
   "source": [
    "O primeiro passo dos nossos cálculos é calcular a eficiência média do coletor em cada dia do ano. Criamos uma função que calcule a eficiência com base nos parâmetros necessários, e aplicamo-la aos nossos dados."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c320ef00-7c36-444f-b553-2b8197bfd9bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "def calc_eficiencia(eta0, alfa1, alfa2, Ti, Tf, G):\n",
    "    eficiencia = eta0 - alfa1*(Tf-Ti)/G - alfa2*(Tf-Ti)**2/G\n",
    "    return eficiencia"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd269462-f7ef-4004-8d5c-d13e5dbb9fc2",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_diaria['Eficiência'] = df_diaria['Temperatura (ºC)'].apply(\n",
    "    lambda Ti: calc_eficiencia(eta0, alfa1, alfa2, Ti, Tf=50, G=700)\n",
    ")\n",
    "df_diaria"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b317fc79-e70d-4a5a-a2b8-008a8920c21f",
   "metadata": {},
   "source": [
    "Agora que temos a eficiência, podemos calcular a energia fornecida pelo coletor."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c6c84b55-15f7-46e1-8b71-cc8073292470",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_diaria['Energia fornecida (kWh)'] = # TODO: calcula a energia fornecida\n",
    "\n",
    "df_diaria"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "672e16c7-f9eb-4fc9-94b4-0fa676b7120e",
   "metadata": {},
   "source": [
    "### **3.** Considerando que o consumo médio diário de água por pessoa é 40 litros a uma temperatura de 50ºC, e considerando um coletor com uma área de 1 m$^2$/pessoa, calcula a energia térmica útil para cada dia do ano."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d18c260c-e103-4ece-af27-e492005bea5d",
   "metadata": {},
   "source": [
    "O primeiro passo é calcular a energia necessária para aquecer a água a cada dia do ano."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "30e9a7b4-c5ba-4607-943b-80ec3a71ff06",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_diaria['Energia necessária (J)'] = # TODO: calcula a energia necessária\n",
    "df_diaria['Energia necessária (kWh)'] = # TODO: converte em kWh\n",
    "\n",
    "df_diaria = df_diaria.drop('Energia necessária (J)', axis=1) # não precisamos da primeira coluna\n",
    "\n",
    "df_diaria"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ad861d1-814d-4497-92ea-3e3ed3dbb9b5",
   "metadata": {},
   "source": [
    "Como determinamos a energia útil agora? Temos três cenários possíveis: a energia fornecida pelo coletor pode ser maior, igual ou menor do que a energia necessária. O que acontece em cada um dos casos?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1067e4d2-8c36-4804-85a2-741c251636f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_diaria['Energia útil (kWh)'] = # TODO: determina a energia útil\n",
    "df_diaria"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c6e9f73-49f2-45f6-95b7-4eb15f30e355",
   "metadata": {},
   "source": [
    "#### a) Apresenta um gráfico que ilustre a energia fornecida, necessária e útil ao longo do ano. O que observas?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94e37962-6c5d-4324-a50d-283bc36df470",
   "metadata": {},
   "outputs": [],
   "source": [
    "# definimos uma função para reutilizar mais à frente\n",
    "def grafico_anual_coletor(df, area=1):\n",
    "    plt.figure(figsize=(10, 5))\n",
    "\n",
    "    plt.plot(df['Energia fornecida (kWh)'], label='Energia fornecida')\n",
    "\n",
    "    # TODO: introduz a energia necessária e a energia útil, bem como os títulos dos eixos\n",
    "    \n",
    "    plt.xlim([df_diaria.index.min(), df_diaria.index.max()])\n",
    "    plt.ylim(bottom=0)\n",
    "    \n",
    "    plt.gca().xaxis.set_major_locator(mdates.MonthLocator())  # Monthly ticks\n",
    "    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))  # Format: \"Jan 01\", \"Feb 01\", etc.\n",
    "    plt.xticks(rotation=90, ha=\"right\")\n",
    "\n",
    "    plt.title(f\"Coletor de {area} m$^2$\")\n",
    "    plt.legend()\n",
    "    plt.grid()\n",
    "    plt.show()\n",
    "\n",
    "grafico_anual_coletor(df_diaria)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c396fa1d-556d-4caa-8bdc-a6ee33ce7067",
   "metadata": {},
   "source": [
    "### **4.** Calcula a eficiência total do sistema para o período de um ano."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d738ea43-e217-4c5b-a94b-ee7a72036fe2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: calcula a eficiência anual\n",
    "eficiencia_anual = \n",
    "print(f\"Eficiência anual: {round(eficiencia_anual, 3)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "93661ffc-1499-4858-ade9-64068fb69042",
   "metadata": {},
   "source": [
    "### **5.** Calcula a fração solar do sistema para o período de um ano."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ec93e692-bf3d-40da-aa1e-95840ffe63d8",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: calcula a fração solar\n",
    "fracao_solar = \n",
    "print(f\"Fração solar: {round(fracao_solar, 3)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8944c7d6-45d1-4d9a-abb0-910cab7b6b2a",
   "metadata": {},
   "source": [
    "### **6.** Considerando que o preço dos coletores é de 1000€/m$^2$ e que têm um tempo de vida de 20 anos, qual é o custo da energia útil?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c2b8cb4-4679-4de7-88a5-7472fb6a759b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: calcula o custo da energia útil\n",
    "custo_E_util = \n",
    "print(f\"Custo: {round(custo_E_util, 2)} €/kWh\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb17025d-c550-49a2-9360-00b87910c564",
   "metadata": {},
   "source": [
    "### **7.** Repete as questões 2 a 6, desta vez considerando diferentes áreas de coletor."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1941a25e-f1c3-44db-8c0d-490dddaa40a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def modelar_coletor(df_, area_coletor, preco=1000):\n",
    "    df = df_[['Irradiação (kWh/m2)', 'Eficiência', 'Energia necessária (kWh)']].copy()\n",
    "\n",
    "    df['Energia fornecida (kWh)'] = df['Eficiência'] * df['Irradiação (kWh/m2)'] * area_coletor\n",
    "    df['Energia útil (kWh)'] = np.minimum(df['Energia fornecida (kWh)'], df['Energia necessária (kWh)'])\n",
    "\n",
    "    grafico_anual_coletor(df, area=area_coletor)\n",
    "    \n",
    "    E_util_anual = df['Energia útil (kWh)'].sum()\n",
    "    irradiacao_anual = df['Irradiação (kWh/m2)'].sum() * area_coletor\n",
    "    E_necessaria_anual = df['Energia necessária (kWh)'].sum()\n",
    "    \n",
    "    eficiencia_anual = E_util_anual / irradiacao_anual\n",
    "    fracao_solar = E_util_anual / E_necessaria_anual\n",
    "    \n",
    "    custo_E_util = preco*area_coletor/(20*E_util_anual)\n",
    "\n",
    "    return eficiencia_anual, fracao_solar, custo_E_util"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "702d1dda-37cb-45da-9b93-bcf49d26cd50",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "results = []\n",
    "\n",
    "for area_coletor in [0.25, 0.5, 1, 1.5, 2, 3, 4, 5, 10]:\n",
    "    eficiencia_anual, fracao_solar, custo_E_util = modelar_coletor(df_diaria, area_coletor)\n",
    "    \n",
    "    results.append({\n",
    "        'Área do coletor (m²)': area_coletor,\n",
    "        'Eficiência anual': eficiencia_anual,\n",
    "        'Fração solar': fracao_solar,\n",
    "        'Custo (€/kWh)': custo_E_util\n",
    "    })\n",
    "\n",
    "df_coletores = pd.DataFrame(results)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa5d4972-181b-4aed-81eb-7a9943c230c4",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_coletores"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c41650e-d5da-457f-b6a0-bb3779bbc02f",
   "metadata": {},
   "source": [
    "#### a) Descreve o que observas para os casos extremos - a menor (0.25 m$^2$) e a maior (10 m$^2$) área consideradas."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65214720-d9f5-4b86-a932-31aee88235ad",
   "metadata": {},
   "source": [
    "#### b) Como variam a eficiência e a fração solar? Porquê?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "266cf7eb-87d8-4fe5-be1b-9f4904731f3c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create the figure and axis\n",
    "fig, ax1 = plt.subplots(figsize=(8, 6))\n",
    "\n",
    "# Plot Fração solar on the first y-axis\n",
    "ax1.plot(df_coletores['Área do coletor (m²)'], df_coletores['Fração solar'], color='tab:green', marker='s', label='Fração solar')\n",
    "ax1.set_xlabel('Área do coletor (m²)')\n",
    "ax1.set_ylabel('Fração solar', color='tab:green')\n",
    "ax1.tick_params(axis='y', labelcolor='tab:green')\n",
    "ax1.set_ylim([0,1.1])\n",
    "\n",
    "# Create a second y-axis for Custo (€/kWh)\n",
    "ax2 = ax1.twinx()\n",
    "ax2.plot(df_coletores['Área do coletor (m²)'], df_coletores['Eficiência anual'], color='tab:red', marker='o', label='Custo (€/kWh)')\n",
    "ax2.set_ylabel('Eficiência anual', color='tab:red')\n",
    "ax2.tick_params(axis='y', labelcolor='tab:red')\n",
    "ax2.set_ylim([0,1.1])\n",
    "\n",
    "ax1.grid(True)\n",
    "\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5e6626a-edff-46ff-b359-ac387dfadc9b",
   "metadata": {},
   "source": [
    "#### c) Como varia o custo em função da fração solar? Apresenta um gráfico."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f0d5ff5c-d522-4ad7-aed5-bd05d6333624",
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO: apresenta um gráfico do custo em função da fração solar. Não te esqueças dos títulos dos eixos :)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62acdd8c-2a1b-412f-9e5b-102350bde50a",
   "metadata": {},
   "source": [
    "#### d) Que valor escolherias para a área? Justifica."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3882c80a-da8b-4be7-a7bd-268dff801774",
   "metadata": {},
   "source": [
    "# Bónus"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1eaaeccc-f4e4-4782-a471-e8d01cb9f952",
   "metadata": {},
   "source": [
    "Para um valor extra, constrói um gráfico diferente dos anteriores que mostre algo interessante relacionado com energia solar fotovoltaica ou térmica, e explica o que ele demonstra :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8f29167c-8556-4f3a-954e-d2bc80a7f021",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}