naohiro701 commited on
Commit
38191ba
·
verified ·
1 Parent(s): 99662df

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +17 -79
app.py CHANGED
@@ -11,29 +11,18 @@ import numpy as np
11
 
12
  # Function to fetch renewable energy data
13
  def get_renewable_energy_data(city_code):
14
- """
15
- Fetch renewable energy data from an external source based on a city code.
16
-
17
- Args:
18
- - city_code (str): The code representing the city for which the renewable energy data is to be fetched.
19
- Returns:
20
- - result_df (DataFrame): A DataFrame containing the energy data with time and capacity factors for each energy type.
21
- - error (str): Error message if the data fetching fails.
22
- """
23
  url = f"https://energy-sustainability.jp/_ajax/renewable_energy/get/?code={city_code}"
24
  response = requests.get(url)
25
  if response.status_code != 200:
26
- return None, "データの取得に失敗しました。" # Data fetch failed.
27
 
28
  data = response.json()
29
  if not data:
30
- return None, "データが見つかりませんでした。" # Data not found.
31
 
32
- # Extract base times from the first energy type.
33
  base_times = data[next(iter(data))]['x']
34
  result_df = pd.DataFrame({"Time": base_times})
35
 
36
- # Loop through each energy type and append hourly capacity factor data.
37
  for energy_type, energy_data in data.items():
38
  if 'x' in energy_data and 'y' in energy_data:
39
  values = energy_data['y']
@@ -43,48 +32,21 @@ def get_renewable_energy_data(city_code):
43
 
44
  # Function to filter numeric columns
45
  def filter_numeric_columns(df):
46
- """
47
- Filters only numeric columns from the provided DataFrame.
48
-
49
- Args:
50
- - df (DataFrame): The DataFrame from which to filter numeric columns.
51
-
52
- Returns:
53
- - DataFrame: A DataFrame containing only numeric columns.
54
- """
55
  numeric_df = df.select_dtypes(include=['number'])
56
  return numeric_df
57
 
58
  # Function to optimize the energy system
59
  def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand):
60
- """
61
- Optimize the energy system using linear programming to minimize cost while meeting demand with renewable sources and batteries.
62
-
63
- Args:
64
- - city_code (str): The code of the city for which energy data is to be optimized.
65
- - solar_cost (float): The cost of solar capacity per MW.
66
- - onshore_wind_cost (float): The cost of onshore wind capacity per MW.
67
- - offshore_wind_cost (float): The cost of offshore wind capacity per MW.
68
- - river_cost (float): The cost of river (hydro) capacity per MW.
69
- - battery_cost (float): The cost of battery capacity per MWh.
70
- - yearly_demand (float): The total yearly demand in TWh/year.
71
- Returns:
72
- - fig (Figure): A plotly figure showing the optimized energy dispatch and state of charge (SOC) over time.
73
- - curtailment_values (list): List of curtailment values for visualization.
74
- - price_per_hour (list): List of estimated electricity price per hour for visualization.
75
- """
76
  data, error = get_renewable_energy_data(city_code)
77
  if error:
78
  st.error(error)
79
  return None, None, None
80
 
81
- # Convert capacity factor columns to numeric values, handling any errors and filling missing data.
82
  for col in data.columns[1:]:
83
  data[col] = pd.to_numeric(data[col], errors='coerce')
84
 
85
- data = data.fillna(0) # Fill missing values with zero.
86
 
87
- # Extract necessary data for optimization.
88
  time_steps = range(len(data['Time']))
89
  solar_cf = data['solar hourly capacity factor']
90
  onshore_wind_cf = data['onshore_wind hourly capacity factor']
@@ -92,7 +54,6 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
92
  river_cf = data['river hourly capacity factor']
93
  demand_cf = data['demand hourly capacity factor']
94
 
95
- # Define regions and technologies.
96
  regions = ['region1']
97
  technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
98
  capacity_factor = {
@@ -102,15 +63,12 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
102
  'river': river_cf
103
  }
104
 
105
- # Cost definitions for renewable capacity and battery.
106
  renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
107
  battery_cost_per_mwh = battery_cost
108
- battery_efficiency = 0.9 # Battery efficiency.
109
 
110
- # Scale demand from capacity factor and yearly demand in TWh/year to hourly demand in MW.
111
  demand = demand_cf * yearly_demand / 100 * 1000 * 1000
112
 
113
- # Define LP variables for renewable capacities, curtailment, battery capacity, charge, discharge, and state of charge (SOC).
114
  renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
115
  [(r, g) for r in regions for g in technologies],
116
  lowBound=0, cat='Continuous')
@@ -122,14 +80,12 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
122
  battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
123
  SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
124
 
125
- # Define the optimization problem: minimize the total system cost.
126
  model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
127
 
128
  model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
129
  for r in regions for g in technologies]) + \
130
  battery_capacity * battery_cost_per_mwh, "TotalCost"
131
 
132
- # Constraints to meet demand, manage curtailment, and update state of charge for the battery.
133
  for r in regions:
134
  for t in time_steps:
135
  model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
@@ -142,10 +98,8 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
142
 
143
  model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
144
 
145
- # Solve the optimization model.
146
  model.solve()
147
 
148
- # Extract optimized supply and battery values.
149
  supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
150
  supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
151
  supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
@@ -156,25 +110,21 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
156
  SOC_values = [SOC[t].varValue for t in time_steps]
157
  curtailment_values = [curtailment[(r, t)].varValue for r in regions for t in time_steps]
158
 
159
- # Calculate price per hour based on demand and generation (simplified example).
160
- price_per_hour = [100 + 0.05 * demand[t] for t in time_steps] # Base price + factor for demand.
161
 
162
- # Normalize state of charge (SOC) to a percentage.
163
  max_SOC = max(SOC_values)
164
  SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
165
 
166
- # Plot energy dispatch.
167
  fig_energy = go.Figure()
168
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0))) # Solar: Gold
169
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_onshore_wind, mode='lines', stackgroup='one', name='Onshore Wind', line=dict(color='#1F78B4', width=0))) # Onshore Wind: Blue
170
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_offshore_wind, mode='lines', stackgroup='one', name='Offshore Wind', line=dict(color='#66C2A5', width=0))) # Offshore Wind: Light Green
171
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_river, mode='lines', stackgroup='one', name='Run of River', line=dict(color='#FF7F00', width=0))) # Run of River: Orange
172
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=battery_discharge_values, mode='lines', stackgroup='one', name='Battery Discharge', fill='tonexty', line=dict(color='#6A3D9A', width=0))) # Battery Discharge: Brown
173
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=battery_charge_values, mode='lines', stackgroup='two', name='Battery Charge', fill='tonexty', line=dict(color='#6A3D9A', width=0))) # Battery Charge: Purple
174
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0))) # Demand: Black
175
- fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0))) # Curtailment: Grey
176
 
177
- # Layout settings for energy dispatch plot.
178
  fig_energy.update_layout(
179
  title_text='Power Supply and Demand',
180
  title_x=0.5,
@@ -188,14 +138,11 @@ def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wi
188
  yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
189
  )
190
 
191
- # Return the figures and other outputs.
192
  return fig_energy, curtailment_values, price_per_hour
193
 
194
- # Streamlit UI for the application
195
  st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
196
  st.title('Renewable Energy System Optimization')
197
 
198
- # Explanation of the project
199
  st.markdown("""
200
  ### Overview
201
  This application is designed to help researchers and policymakers explore and optimize renewable energy systems for a specified region. By inputting cost parameters for different renewable energy sources and energy storage systems, the application determines the optimal mix of resources to meet energy demand while minimizing cost.
@@ -203,7 +150,6 @@ The optimization problem is solved using linear programming, ensuring a balance
203
  The visualizations provided help to better understand how different energy sources contribute to the overall power supply, how energy storage systems are utilized, and the impact of cost variations on energy prices.
204
  """)
205
 
206
- # Input fields for the user
207
  with st.sidebar:
208
  st.header('Input Parameters')
209
  city_code = st.text_input("Enter City Code", value="")
@@ -214,17 +160,14 @@ with st.sidebar:
214
  battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0, help="Estimated average cost of battery storage per MWh")
215
  yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0, help="Total yearly power demand in TWh")
216
 
217
- # Button to trigger optimization
218
  if st.button('Calculate Optimal Energy Mix'):
219
  fig, curtailment_values, price_per_hour = optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand)
220
  if fig:
221
  st.plotly_chart(fig, use_container_width=True, height=800)
222
 
223
- # Additional analysis and visualizations
224
  st.markdown("### Additional Analysis")
225
  st.markdown("The following plots provide additional insights into the renewable energy mix, curtailment, and electricity price variations.")
226
 
227
- # Data for additional visualizations
228
  renewable_data = {
229
  'Solar': solar_cost,
230
  'Onshore Wind': onshore_wind_cost,
@@ -233,21 +176,17 @@ if st.button('Calculate Optimal Energy Mix'):
233
  }
234
  cost_df = pd.DataFrame(list(renewable_data.items()), columns=['Technology', 'Cost (¥/MW)'])
235
 
236
- # Plot cost comparison
237
  fig_cost = px.bar(cost_df, x='Technology', y='Cost (¥/MW)', color='Technology', title='Cost Comparison of Different Renewable Technologies', template='plotly_white')
238
  st.plotly_chart(fig_cost, use_container_width=True, height=800)
239
 
240
- # Plot curtailment over time
241
  curtailment_df = pd.DataFrame({"Time": fig.data[0].x, "Curtailment (MW)": curtailment_values})
242
  fig_curtailment = px.line(curtailment_df, x='Time', y='Curtailment (MW)', title='Curtailment Over Time', template='plotly_white')
243
  st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
244
 
245
- # Plot electricity price over time
246
  price_df = pd.DataFrame({"Time": fig.data[0].x, "Electricity Price (¥/MWh)": price_per_hour})
247
  fig_price = px.line(price_df, x='Time', y='Electricity Price (¥/MWh)', title='Electricity Price Variation Over Time', template='plotly_white')
248
  st.plotly_chart(fig_price, use_container_width=True, height=800)
249
 
250
- # Correlation analysis of renewable capacity factors
251
  if city_code:
252
  st.markdown("### Correlation Between Renewable Energy Sources")
253
  energy_data_df, error = get_renewable_energy_data(city_code)
@@ -256,7 +195,6 @@ if st.button('Calculate Optimal Energy Mix'):
256
  else:
257
  numeric_energy_data_df = filter_numeric_columns(energy_data_df)
258
 
259
- # Handling missing values by filling them with 0.
260
  numeric_energy_data_df = numeric_energy_data_df.fillna(0)
261
 
262
  correlation_matrix = numeric_energy_data_df.corr()
@@ -265,13 +203,13 @@ if st.button('Calculate Optimal Energy Mix'):
265
  fig_corr = px.imshow(correlation_matrix, title='Correlation Matrix of Renewable Capacity Factors', labels={'color': 'Correlation'}, template='plotly_white')
266
  st.plotly_chart(fig_corr, use_container_width=True, height=800)
267
 
268
- # Plot heatmaps for renewable energy and demand characteristics
269
  st.markdown("### Heatmap of Renewable Energy and Demand Characteristics")
270
  hourly_data = numeric_energy_data_df.copy()
271
- hourly_data['Date'] = pd.to_datetime(data['Time']).dt.date
272
- hourly_data['Hour'] = pd.to_datetime(data['Time']).dt.hour
 
273
 
274
- for column in hourly_data.columns[2:]: # Skipping 'Date' and 'Hour' columns
275
  pivot_df = hourly_data.pivot_table(index='Hour', columns='Date', values=column, aggfunc=np.mean)
276
  fig_heatmap = px.imshow(pivot_df, title=f"Heatmap of {column}", labels={'color': column}, template='plotly_white', aspect='auto')
277
  st.plotly_chart(fig_heatmap, use_container_width=True, height=800)
 
11
 
12
  # Function to fetch renewable energy data
13
  def get_renewable_energy_data(city_code):
 
 
 
 
 
 
 
 
 
14
  url = f"https://energy-sustainability.jp/_ajax/renewable_energy/get/?code={city_code}"
15
  response = requests.get(url)
16
  if response.status_code != 200:
17
+ return None, "データの取得に失敗しました。"
18
 
19
  data = response.json()
20
  if not data:
21
+ return None, "データが見つかりませんでした。"
22
 
 
23
  base_times = data[next(iter(data))]['x']
24
  result_df = pd.DataFrame({"Time": base_times})
25
 
 
26
  for energy_type, energy_data in data.items():
27
  if 'x' in energy_data and 'y' in energy_data:
28
  values = energy_data['y']
 
32
 
33
  # Function to filter numeric columns
34
  def filter_numeric_columns(df):
 
 
 
 
 
 
 
 
 
35
  numeric_df = df.select_dtypes(include=['number'])
36
  return numeric_df
37
 
38
  # Function to optimize the energy system
39
  def optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  data, error = get_renewable_energy_data(city_code)
41
  if error:
42
  st.error(error)
43
  return None, None, None
44
 
 
45
  for col in data.columns[1:]:
46
  data[col] = pd.to_numeric(data[col], errors='coerce')
47
 
48
+ data = data.fillna(0)
49
 
 
50
  time_steps = range(len(data['Time']))
51
  solar_cf = data['solar hourly capacity factor']
52
  onshore_wind_cf = data['onshore_wind hourly capacity factor']
 
54
  river_cf = data['river hourly capacity factor']
55
  demand_cf = data['demand hourly capacity factor']
56
 
 
57
  regions = ['region1']
58
  technologies = ['solar', 'onshore_wind', 'offshore_wind', 'river']
59
  capacity_factor = {
 
63
  'river': river_cf
64
  }
65
 
 
66
  renewable_capacity_cost = {'solar': solar_cost, 'onshore_wind': onshore_wind_cost, 'offshore_wind': offshore_wind_cost, 'river': river_cost}
67
  battery_cost_per_mwh = battery_cost
68
+ battery_efficiency = 0.9
69
 
 
70
  demand = demand_cf * yearly_demand / 100 * 1000 * 1000
71
 
 
72
  renewable_capacity = pulp.LpVariable.dicts("renewable_capacity",
73
  [(r, g) for r in regions for g in technologies],
74
  lowBound=0, cat='Continuous')
 
80
  battery_discharge = pulp.LpVariable.dicts("battery_discharge", time_steps, lowBound=0, cat='Continuous')
81
  SOC = pulp.LpVariable.dicts("SOC", time_steps, lowBound=0, cat='Continuous')
82
 
 
83
  model = pulp.LpProblem("EnergySystemOptimizationWithBattery", pulp.LpMinimize)
84
 
85
  model += pulp.lpSum([renewable_capacity[(r, g)] * renewable_capacity_cost[g]
86
  for r in regions for g in technologies]) + \
87
  battery_capacity * battery_cost_per_mwh, "TotalCost"
88
 
 
89
  for r in regions:
90
  for t in time_steps:
91
  model += pulp.lpSum([renewable_capacity[(r, g)] * capacity_factor[g][t]
 
98
 
99
  model += SOC[t] <= battery_capacity, f"SOCUpperBound_{t}"
100
 
 
101
  model.solve()
102
 
 
103
  supply_solar = solar_cf * renewable_capacity[('region1', 'solar')].varValue
104
  supply_onshore_wind = onshore_wind_cf * renewable_capacity[('region1', 'onshore_wind')].varValue
105
  supply_offshore_wind = offshore_wind_cf * renewable_capacity[('region1', 'offshore_wind')].varValue
 
110
  SOC_values = [SOC[t].varValue for t in time_steps]
111
  curtailment_values = [curtailment[(r, t)].varValue for r in regions for t in time_steps]
112
 
113
+ price_per_hour = [100 + 0.05 * demand[t] for t in time_steps]
 
114
 
 
115
  max_SOC = max(SOC_values)
116
  SOC_normalized = [(soc / max_SOC) * 100 for soc in SOC_values] if max_SOC > 0 else [0] * len(SOC_values)
117
 
 
118
  fig_energy = go.Figure()
119
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_solar, mode='lines', stackgroup='one', name='Solar', line=dict(color='#FFD700', width=0)))
120
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_onshore_wind, mode='lines', stackgroup='one', name='Onshore Wind', line=dict(color='#1F78B4', width=0)))
121
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_offshore_wind, mode='lines', stackgroup='one', name='Offshore Wind', line=dict(color='#66C2A5', width=0)))
122
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=supply_river, mode='lines', stackgroup='one', name='Run of River', line=dict(color='#FF7F00', width=0)))
123
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=battery_discharge_values, mode='lines', stackgroup='one', name='Battery Discharge', fill='tonexty', line=dict(color='#6A3D9A', width=0)))
124
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=battery_charge_values, mode='lines', stackgroup='two', name='Battery Charge', fill='tonexty', line=dict(color='#6A3D9A', width=0)))
125
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=-demand, mode='lines', stackgroup='two', name='Demand', line=dict(color='black', width=0)))
126
+ fig_energy.add_trace(go.Scatter(x=data['Time'], y=curtailment_values, mode='lines', stackgroup='two', name='Curtailment', line=dict(color='#aaaaaa', width=0)))
127
 
 
128
  fig_energy.update_layout(
129
  title_text='Power Supply and Demand',
130
  title_x=0.5,
 
138
  yaxis=dict(showgrid=True, gridwidth=0.5, gridcolor='lightgray')
139
  )
140
 
 
141
  return fig_energy, curtailment_values, price_per_hour
142
 
 
143
  st.set_page_config(page_title='Renewable Energy System Optimization', layout='wide')
144
  st.title('Renewable Energy System Optimization')
145
 
 
146
  st.markdown("""
147
  ### Overview
148
  This application is designed to help researchers and policymakers explore and optimize renewable energy systems for a specified region. By inputting cost parameters for different renewable energy sources and energy storage systems, the application determines the optimal mix of resources to meet energy demand while minimizing cost.
 
150
  The visualizations provided help to better understand how different energy sources contribute to the overall power supply, how energy storage systems are utilized, and the impact of cost variations on energy prices.
151
  """)
152
 
 
153
  with st.sidebar:
154
  st.header('Input Parameters')
155
  city_code = st.text_input("Enter City Code", value="")
 
160
  battery_cost = st.number_input("Battery Cost (¥/MWh)", value=80.0, help="Estimated average cost of battery storage per MWh")
161
  yearly_demand = st.number_input("Yearly Power Demand (TWh/year)", value=15.0, help="Total yearly power demand in TWh")
162
 
 
163
  if st.button('Calculate Optimal Energy Mix'):
164
  fig, curtailment_values, price_per_hour = optimize_energy_system(city_code, solar_cost, onshore_wind_cost, offshore_wind_cost, river_cost, battery_cost, yearly_demand)
165
  if fig:
166
  st.plotly_chart(fig, use_container_width=True, height=800)
167
 
 
168
  st.markdown("### Additional Analysis")
169
  st.markdown("The following plots provide additional insights into the renewable energy mix, curtailment, and electricity price variations.")
170
 
 
171
  renewable_data = {
172
  'Solar': solar_cost,
173
  'Onshore Wind': onshore_wind_cost,
 
176
  }
177
  cost_df = pd.DataFrame(list(renewable_data.items()), columns=['Technology', 'Cost (¥/MW)'])
178
 
 
179
  fig_cost = px.bar(cost_df, x='Technology', y='Cost (¥/MW)', color='Technology', title='Cost Comparison of Different Renewable Technologies', template='plotly_white')
180
  st.plotly_chart(fig_cost, use_container_width=True, height=800)
181
 
 
182
  curtailment_df = pd.DataFrame({"Time": fig.data[0].x, "Curtailment (MW)": curtailment_values})
183
  fig_curtailment = px.line(curtailment_df, x='Time', y='Curtailment (MW)', title='Curtailment Over Time', template='plotly_white')
184
  st.plotly_chart(fig_curtailment, use_container_width=True, height=800)
185
 
 
186
  price_df = pd.DataFrame({"Time": fig.data[0].x, "Electricity Price (¥/MWh)": price_per_hour})
187
  fig_price = px.line(price_df, x='Time', y='Electricity Price (¥/MWh)', title='Electricity Price Variation Over Time', template='plotly_white')
188
  st.plotly_chart(fig_price, use_container_width=True, height=800)
189
 
 
190
  if city_code:
191
  st.markdown("### Correlation Between Renewable Energy Sources")
192
  energy_data_df, error = get_renewable_energy_data(city_code)
 
195
  else:
196
  numeric_energy_data_df = filter_numeric_columns(energy_data_df)
197
 
 
198
  numeric_energy_data_df = numeric_energy_data_df.fillna(0)
199
 
200
  correlation_matrix = numeric_energy_data_df.corr()
 
203
  fig_corr = px.imshow(correlation_matrix, title='Correlation Matrix of Renewable Capacity Factors', labels={'color': 'Correlation'}, template='plotly_white')
204
  st.plotly_chart(fig_corr, use_container_width=True, height=800)
205
 
 
206
  st.markdown("### Heatmap of Renewable Energy and Demand Characteristics")
207
  hourly_data = numeric_energy_data_df.copy()
208
+ hourly_data['Time'] = pd.to_datetime(data['Time'], errors='coerce')
209
+ hourly_data['Date'] = hourly_data['Time'].dt.date
210
+ hourly_data['Hour'] = hourly_data['Time'].dt.hour
211
 
212
+ for column in hourly_data.columns[2:]:
213
  pivot_df = hourly_data.pivot_table(index='Hour', columns='Date', values=column, aggfunc=np.mean)
214
  fig_heatmap = px.imshow(pivot_df, title=f"Heatmap of {column}", labels={'color': column}, template='plotly_white', aspect='auto')
215
  st.plotly_chart(fig_heatmap, use_container_width=True, height=800)