@@ -15,7 +15,7 @@ def plot_trace(
1515 default_visible : Optional [str ] = None ,
1616 scale : Optional [float ] = None ,
1717 y_axis_title : Optional [str ] = None ,
18- dataset_name : Optional [str ] = None
18+ dataset_name : Optional [str ] = None ,
1919) -> Figure :
2020 """Plot a Vessim Trace using Plotly.
2121
@@ -60,22 +60,15 @@ def plot_trace(
6060 go .Scatter (
6161 x = df .index ,
6262 y = df [column_name ],
63- name = column_name if len (df .columns ) == 1 else "Carbon Intensity"
63+ name = column_name if len (df .columns ) == 1 else "Carbon Intensity" ,
6464 )
6565 )
6666 showlegend = False
6767 else :
6868 # Multi-column datasets (like solar data)
6969 for col in df .columns :
7070 visible = True if col == default_visible else "legendonly"
71- fig .add_trace (
72- go .Scatter (
73- x = df .index ,
74- y = df [col ],
75- visible = visible ,
76- name = col
77- )
78- )
71+ fig .add_trace (go .Scatter (x = df .index , y = df [col ], visible = visible , name = col ))
7972 showlegend = True
8073
8174 # Update layout
@@ -84,9 +77,9 @@ def plot_trace(
8477 xaxis_title = "Date" ,
8578 yaxis_title = y_axis_title ,
8679 showlegend = showlegend ,
87- hovermode = ' x unified' if len (df .columns ) > 1 else 'x' ,
80+ hovermode = " x unified" if len (df .columns ) > 1 else "x" ,
8881 margin = {"l" : 0 , "t" : 40 , "b" : 0 , "r" : 0 },
89- autosize = True
82+ autosize = True ,
9083 )
9184
9285 return fig
@@ -98,10 +91,9 @@ def plot_microgrid_trace(
9891 actors : Optional [List [str ]] = None ,
9992 include_system_power : bool = True ,
10093 include_storage : bool = True ,
101- title : Optional [str ] = None ,
102- height : int = 800 ,
94+ height : int = 600 ,
10395 actor_colors : Optional [dict ] = None ,
104- layout : str = "detailed"
96+ layout : str = "detailed" ,
10597) -> Figure :
10698 """Plot microgrid trace with actors, system power, and battery state.
10799
@@ -114,7 +106,6 @@ def plot_microgrid_trace(
114106 actors: List of actor names to plot. If None, auto-detects from columns ending in '.p'
115107 include_system_power: Whether to include the system power (p_delta, p_grid)
116108 include_storage: Whether to include the storage subplot (storage.soc)
117- title: Overall plot title. If None, uses auto-generated title
118109 height: Total plot height in pixels
119110 actor_colors: Dict mapping actor names to colors. If None, uses default Plotly colors
120111 layout: "detailed" for 3 subplots, "overview" for 2 subplots (default: "detailed")
@@ -137,40 +128,38 @@ def plot_microgrid_trace(
137128 """
138129 # Auto-detect actors if not specified
139130 if actors is None :
140- actors = [col .replace ('.p' , '' ) for col in df .columns if col .endswith ('.p' )]
131+ actors = [col .replace (".p" , "" ) for col in df .columns if col .endswith (".p" )]
141132
142133 # Handle layout options
143134 if layout == "overview" :
144135 # Use overview layout: combine actors and system power in one subplot
145- has_storage = include_storage and ' storage.soc' in df .columns
136+ has_storage = include_storage and " storage.soc" in df .columns
146137 subplot_count = 2 if has_storage else 1
147-
138+
148139 subplot_titles = ["Power Overview" ]
149140 if has_storage :
150141 subplot_titles .append ("Battery State of Charge" )
151-
142+
152143 row_heights = [0.67 , 0.33 ] if subplot_count == 2 else [1.0 ]
153-
144+
154145 else : # detailed layout
155146 # Determine subplot configuration - separate subplots
156147 subplot_count = 1 # Always include actors
157148 if include_system_power :
158149 subplot_count += 1
159- if include_storage and ' storage.soc' in df .columns :
150+ if include_storage and " storage.soc" in df .columns :
160151 subplot_count += 1
161152
162153 # Create subplot titles
163154 subplot_titles = ["Actor Power" ]
164155 if include_system_power :
165156 subplot_titles .append ("System Power" )
166- if include_storage and ' storage.soc' in df .columns :
157+ if include_storage and " storage.soc" in df .columns :
167158 subplot_titles .append ("Battery State of Charge" )
168159
169160 # Calculate height ratios - give more space to actors plot
170161 row_heights = (
171- [0.5 ] + [0.5 / (subplot_count - 1 )] * (subplot_count - 1 )
172- if subplot_count > 1
173- else [1 ]
162+ [0.5 ] + [0.5 / (subplot_count - 1 )] * (subplot_count - 1 ) if subplot_count > 1 else [1 ]
174163 )
175164
176165 # Create subplots
@@ -180,18 +169,18 @@ def plot_microgrid_trace(
180169 shared_xaxes = True ,
181170 subplot_titles = subplot_titles ,
182171 row_heights = row_heights ,
183- vertical_spacing = 0.08
172+ vertical_spacing = 0.08 ,
184173 )
185174
186175 # Define default colors for common actor types
187176 default_colors = {
188- ' server' : ' #d62728' , # red
189- ' solar_panel' : ' #ff7f0e' , # orange
190- ' solar' : ' #ff7f0e' , # orange
191- ' wind' : ' #2ca02c' , # green
192- ' storage' : ' #9467bd' , # purple
193- ' load' : ' #8c564b' , # brown
194- ' battery' : ' #9467bd' , # purple
177+ " server" : " #d62728" , # red
178+ " solar_panel" : " #ff7f0e" , # orange
179+ " solar" : " #ff7f0e" , # orange
180+ " wind" : " #2ca02c" , # green
181+ " storage" : " #9467bd" , # purple
182+ " load" : " #8c564b" , # brown
183+ " battery" : " #9467bd" , # purple
195184 }
196185
197186 current_row = 1
@@ -210,12 +199,12 @@ def plot_microgrid_trace(
210199 color = default_colors [actor ]
211200
212201 # Create display name
213- display_name = actor .replace ('_' , ' ' ).title ()
202+ display_name = actor .replace ("_" , " " ).title ()
214203 if layout == "overview" :
215204 # Match notebook naming
216- if ' server' in actor .lower ():
205+ if " server" in actor .lower ():
217206 display_name = f"{ display_name } power"
218- elif ' solar' in actor .lower ():
207+ elif " solar" in actor .lower ():
219208 display_name = f"{ display_name } power"
220209
221210 fig .add_trace (
@@ -224,146 +213,128 @@ def plot_microgrid_trace(
224213 y = df [actor_col ],
225214 name = display_name ,
226215 line = dict (color = color ) if color else {},
227- hovertemplate = f"{ actor } : %{{y:.1f}} W<extra></extra>"
216+ hovertemplate = f"{ actor } : %{{y:.1f}} W<extra></extra>" ,
228217 ),
229218 row = current_row ,
230- col = 1
219+ col = 1 ,
231220 )
232221
233222 # Add system power to first subplot if overview layout
234223 if layout == "overview" and include_system_power :
235- if ' p_delta' in df .columns :
224+ if " p_delta" in df .columns :
236225 fig .add_trace (
237226 go .Scatter (
238- x = df .index ,
239- y = df ['p_delta' ],
240- name = "Delta power" ,
241- line = dict (color = 'gray' )
227+ x = df .index , y = df ["p_delta" ], name = "Delta power" , line = dict (color = "gray" )
242228 ),
243229 row = current_row ,
244- col = 1
230+ col = 1 ,
245231 )
246-
247- if ' p_grid' in df .columns :
232+
233+ if " p_grid" in df .columns :
248234 fig .add_trace (
249- go .Scatter (
250- x = df .index ,
251- y = df ['p_grid' ],
252- name = "Grid power" ,
253- line = dict (color = 'blue' )
254- ),
235+ go .Scatter (x = df .index , y = df ["p_grid" ], name = "Grid power" , line = dict (color = "blue" )),
255236 row = current_row ,
256- col = 1
237+ col = 1 ,
257238 )
258239
259240 # Format first subplot
260241 fig .update_yaxes (title_text = "Power (W)" , row = current_row , col = 1 )
261242 fig .update_xaxes (
262- showgrid = True , gridwidth = 1 , gridcolor = ' rgba(128,128,128,0.3)' , row = current_row , col = 1
243+ showgrid = True , gridwidth = 1 , gridcolor = " rgba(128,128,128,0.3)" , row = current_row , col = 1
263244 )
264245 fig .update_yaxes (
265- showgrid = True , gridwidth = 1 , gridcolor = ' rgba(128,128,128,0.3)' , row = current_row , col = 1
246+ showgrid = True , gridwidth = 1 , gridcolor = " rgba(128,128,128,0.3)" , row = current_row , col = 1
266247 )
267248
268249 current_row += 1
269250
270251 # 2. System Power Plot (detailed layout only)
271252 if layout == "detailed" and include_system_power and current_row <= subplot_count :
272- if ' p_delta' in df .columns :
253+ if " p_delta" in df .columns :
273254 fig .add_trace (
274255 go .Scatter (
275256 x = df .index ,
276- y = df [' p_delta' ],
257+ y = df [" p_delta" ],
277258 name = "Delta Power" ,
278- line = dict (color = ' gray' ),
279- hovertemplate = "Delta Power: %{y:.1f} W<extra></extra>"
259+ line = dict (color = " gray" ),
260+ hovertemplate = "Delta Power: %{y:.1f} W<extra></extra>" ,
280261 ),
281262 row = current_row ,
282- col = 1
263+ col = 1 ,
283264 )
284265
285- if ' p_grid' in df .columns :
266+ if " p_grid" in df .columns :
286267 fig .add_trace (
287268 go .Scatter (
288269 x = df .index ,
289- y = df [' p_grid' ],
270+ y = df [" p_grid" ],
290271 name = "Grid Power" ,
291- line = dict (color = ' blue' ),
292- hovertemplate = "Grid Power: %{y:.1f} W<extra></extra>"
272+ line = dict (color = " blue" ),
273+ hovertemplate = "Grid Power: %{y:.1f} W<extra></extra>" ,
293274 ),
294275 row = current_row ,
295- col = 1
276+ col = 1 ,
296277 )
297278
298279 fig .update_yaxes (title_text = "Power (W)" , row = current_row , col = 1 )
299280 fig .update_xaxes (
300- showgrid = True , gridwidth = 1 , gridcolor = ' rgba(128,128,128,0.3)' , row = current_row , col = 1
281+ showgrid = True , gridwidth = 1 , gridcolor = " rgba(128,128,128,0.3)" , row = current_row , col = 1
301282 )
302283 fig .update_yaxes (
303- showgrid = True , gridwidth = 1 , gridcolor = ' rgba(128,128,128,0.3)' , row = current_row , col = 1
284+ showgrid = True , gridwidth = 1 , gridcolor = " rgba(128,128,128,0.3)" , row = current_row , col = 1
304285 )
305286
306287 current_row += 1
307288
308289 # 3. Battery State of Charge Plot
309- if include_storage and ' storage.soc' in df .columns and current_row <= subplot_count :
290+ if include_storage and " storage.soc" in df .columns and current_row <= subplot_count :
310291 # Main SoC trace
311292 fig .add_trace (
312293 go .Scatter (
313294 x = df .index ,
314- y = df [' storage.soc' ] * 100 ,
295+ y = df [" storage.soc" ] * 100 ,
315296 name = "Battery SoC" ,
316- line = dict (color = ' green' ),
317- fill = ' tonexty' if len (fig .data ) == 0 else ' tozeroy' ,
318- fillcolor = ' rgba(0,128,0,0.1)' ,
319- hovertemplate = "SoC: %{y:.1f}%<extra></extra>"
297+ line = dict (color = " green" ),
298+ fill = " tonexty" if len (fig .data ) == 0 else " tozeroy" ,
299+ fillcolor = " rgba(0,128,0,0.1)" ,
300+ hovertemplate = "SoC: %{y:.1f}%<extra></extra>" ,
320301 ),
321302 row = current_row ,
322- col = 1
303+ col = 1 ,
323304 )
324305
325306 # Add minimum SoC line if available
326- if ' storage.min_soc' in df .columns :
327- min_soc_value = df [' storage.min_soc' ].iloc [0 ] * 100
307+ if " storage.min_soc" in df .columns :
308+ min_soc_value = df [" storage.min_soc" ].iloc [0 ] * 100
328309 fig .add_hline (
329310 y = min_soc_value ,
330311 line_dash = "dash" ,
331312 line_color = "gray" ,
332313 annotation_text = f"Min SoC ({ min_soc_value :.0f} %)" ,
333314 annotation_position = "top right" ,
334315 row = current_row ,
335- col = 1
316+ col = 1 ,
336317 )
337318
338319 fig .update_yaxes (title_text = "State of Charge (%)" , range = [0 , 100 ], row = current_row , col = 1 )
339320 fig .update_xaxes (
340- showgrid = True , gridwidth = 1 , gridcolor = ' rgba(128,128,128,0.3)' , row = current_row , col = 1
321+ showgrid = True , gridwidth = 1 , gridcolor = " rgba(128,128,128,0.3)" , row = current_row , col = 1
341322 )
342323 fig .update_yaxes (
343- showgrid = True , gridwidth = 1 , gridcolor = ' rgba(128,128,128,0.3)' , row = current_row , col = 1
324+ showgrid = True , gridwidth = 1 , gridcolor = " rgba(128,128,128,0.3)" , row = current_row , col = 1
344325 )
345326
346- # Auto-generate title if not provided
347- if title is None :
348- if layout == "overview" :
349- title = "Solar vs Grid Power Over 24 Hours" if include_storage else "Power Overview"
350- else :
351- title = "Simulation Results"
352-
353327 # Update overall layout
354328 fig .update_layout (
355- title = title ,
356329 height = height ,
357- hovermode = ' x unified' ,
330+ hovermode = " x unified" ,
358331 showlegend = True ,
359- legend = dict (
360- orientation = "h" ,
361- yanchor = "bottom" ,
362- y = 1.02 ,
363- xanchor = "right" ,
364- x = 1
365- ) if layout == "detailed" else None ,
366- margin = dict (l = 0 , t = 60 , b = 0 , r = 0 ) if layout == "overview" else None
332+ legend = (
333+ dict (orientation = "h" , yanchor = "bottom" , y = 1.02 , xanchor = "right" , x = 1 )
334+ if layout == "detailed"
335+ else None
336+ ),
337+ margin = dict (l = 0 , t = 60 , b = 0 , r = 0 ) if layout == "overview" else None ,
367338 )
368339
369340 # Format x-axis for bottom subplot only
@@ -372,7 +343,6 @@ def plot_microgrid_trace(
372343 return fig
373344
374345
375-
376346def _generate_title (dataset_name : str ) -> str :
377347 """Generate a title from dataset name."""
378348 if "solcast2022_global" in dataset_name :
@@ -397,4 +367,3 @@ def _detect_y_axis_title(dataset_name: str, scale: Optional[float] = None) -> st
397367 return "g/kWh"
398368 else :
399369 return "Value"
400-
0 commit comments