Skip to content

Commit b3edf7a

Browse files
committed
Gantt Chart support for Task Class
1 parent ae35d72 commit b3edf7a

File tree

4 files changed

+162
-12
lines changed

4 files changed

+162
-12
lines changed

famodel/irma/calwave_task1.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
from calwave_irma import Scenario
99
import calwave_chart as chart
1010
# from calwave_task import Task # calwave_task module (Felipe)
11-
from task import Task as Task # generic Task module ( Rudy )
11+
from task import Task # generic Task module ( Rudy )
12+
13+
import matplotlib.pyplot as plt
1214

1315
sc = Scenario() # now sc exists in *this* session
1416

@@ -195,11 +197,15 @@ def assign_actions(sc: Scenario, actions: dict):
195197

196198
# 5) Build Task
197199
task1 = Task(name='calwave_task1', actions=sc.actions)
198-
task1.getSequenceGraph()
200+
201+
task1.updateTaskTime(newStart=10)
202+
203+
# 6) Build the Gantt chart
204+
task1.GanttChart(color_by='asset')
199205
plt.show()
200-
# task1.updateTaskTime(newStart=10)
201206

202-
# 6) build the chart input directly from the Task and plot #TODO: Rudy / Improve this later (maybe include it in Task.py/Scenario and let it plot the absolute time instead of relative time)
207+
# Old chart building code:
208+
# 7) build the chart input directly from the Task and plot #TODO: Rudy / Improve this later (maybe include it in Task.py/Scenario and let it plot the absolute time instead of relative time)
203209
chart_view = chart.view_from_task(task1, sc, title='CalWave Task 1 - Anchor installation plan')
204210
chart.plot_task(chart_view, outpath='calwave_task1_chart.png')
205211

famodel/irma/calwave_vessels.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
San_Diego:
44
# Crane barge for anchor handling
5+
name: San_Diego
56
type: crane_barge
67
transport:
78
homeport: national_city
@@ -40,6 +41,7 @@ San_Diego:
4041

4142
Jag:
4243
# Pacific Maritime Group tugboat assisting DB San Diego
44+
name: Jag
4345
type: tug
4446
transport:
4547
homeport: national_city
@@ -67,6 +69,7 @@ Jag:
6769

6870
Beyster:
6971
# Primary support vessel
72+
name: Beyster
7073
type: research_vessel
7174
transport:
7275
homeport: point_loma

famodel/irma/task.py

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ def updateTaskTime(self, newStart=0.0):
318318

319319
# Update action start times
320320
for action in self.actions_ti:
321-
self.actions_ti[action] += time_shift
321+
self.actions_ti[action] += self.ti
322322

323323

324324

@@ -358,3 +358,137 @@ def get_row(self, assets):
358358

359359
return np.zeros((len(assets), 2)) # placeholder, replace with actual matrix
360360

361+
362+
def GanttChart(self, start_at_zero=True, color_by=None):
363+
'''Generate a Gantt chart for the task showing the schedule of actions.
364+
365+
Returns
366+
-------
367+
fig : matplotlib.figure.Figure
368+
The figure object containing the Gantt chart.
369+
ax : matplotlib.axes.Axes
370+
The axes object containing the Gantt chart.
371+
'''
372+
373+
# --- color palette ---
374+
colors = [
375+
"lime", "orange", "magenta", "blue",
376+
"red", "yellow", "cyan", "purple"
377+
]
378+
379+
fig, ax = plt.subplots(figsize=(10, 10))
380+
381+
# Prepare data for Gantt chart
382+
action_names = list(self.actions.keys())
383+
start_times = [self.actions_ti[name] for name in action_names]
384+
durations = [self.actions[name].duration for name in action_names]
385+
386+
# Get asset information from action.assets
387+
all_assets = set()
388+
all_roles = set()
389+
for action in self.actions.values():
390+
for role, asset in action.assets.items():
391+
all_assets.add(asset['name'])
392+
all_roles.add(role)
393+
394+
# Assign colors
395+
if color_by == 'asset':
396+
asset_list = list(all_assets)
397+
color_dict = {asset: colors[i] for i, asset in enumerate(asset_list)}
398+
elif color_by == 'role':
399+
# Flip the colors
400+
colors = colors[::-1]
401+
role_list = list(all_roles)
402+
color_dict = {role: colors[i] for i, role in enumerate(role_list)}
403+
404+
# Generate vertical lines to indicate the start and finish of the whole task
405+
ax.axvline(x=self.ti, ymin=0, ymax=len(action_names), color='black', linestyle='-', linewidth=2.0)
406+
ax.axvline(x=self.tf, ymin=0, ymax=len(action_names), color='black', linestyle='-', linewidth=2.0)
407+
408+
# Create bars for each action
409+
ht = 0.4
410+
for i, (name, start, duration) in enumerate(zip(action_names, start_times, durations)):
411+
opp_i = len(action_names) - i - 1 # to have first action on top
412+
action = self.actions[name]
413+
assets = list({asset['name'] for asset in action.assets.values()})
414+
roles = list({role for role in action.assets.keys()})
415+
416+
assets = list(set(assets)) # Remove duplicates from assets
417+
418+
n_assets = len(assets)
419+
n_roles = len(roles)
420+
421+
if color_by is None:
422+
ax.barh(opp_i, duration, color='cyan', left=start, height=ht, align='center')
423+
elif color_by == 'asset':
424+
# Compute vertical offsets if multiple assets
425+
if n_assets == 0:
426+
# No assets info
427+
ax.barh(i, duration, left=start, height=ht, color='cyan', align='center')
428+
else:
429+
sub_ht = ht / n_assets
430+
for j, asset in enumerate(assets):
431+
bottom = opp_i - ht/2 + j * sub_ht
432+
color = color_dict.get(asset, 'gray')
433+
ax.barh(bottom + sub_ht/2, duration, left=start, height=sub_ht * 0.9,
434+
color=color, edgecolor='k', linewidth=0.3, align='center')
435+
elif color_by == 'role':
436+
# Compute vertical offsets if multiple roles
437+
if n_roles == 0:
438+
# No roles info
439+
ax.barh(opp_i, duration, left=start, height=ht, color='cyan', align='center')
440+
else:
441+
sub_ht = ht / n_roles
442+
for j, role in enumerate(roles):
443+
bottom = opp_i - ht/2 + j * sub_ht
444+
color = color_dict.get(role, 'gray')
445+
ax.barh(bottom + sub_ht/2, duration, left=start, height=sub_ht * 0.9,
446+
color=color, edgecolor='k', linewidth=0.3, align='center')
447+
else:
448+
color_by = None
449+
raise Warning(f"color_by option '{color_by}' not recognized. Use 'asset', 'role'. None will be used")
450+
451+
ax.text(self.ti, opp_i, f' {name}', va='center', ha='left', color='black')
452+
ax.axhline(y=opp_i - ht/2, xmin=0, xmax=self.tf, color='gray', linestyle='--', linewidth=0.5)
453+
ax.axhline(y=opp_i + ht/2, xmin=0, xmax=self.tf, color='gray', linestyle='--', linewidth=0.5)
454+
ax.axvline(x=start, ymin=0, ymax=len(action_names), color='gray', linestyle='--', linewidth=0.5)
455+
456+
# Set y-ticks and labels
457+
ax.set_yticks(range(len(action_names)))
458+
ax.set_yticklabels([])
459+
460+
# Set labels and title
461+
ax.set_xlabel('time (hrs.)')
462+
ax.set_title(f'Gantt Chart for Task: {self.name}')
463+
464+
if color_by == 'asset':
465+
handles = [plt.Rectangle((0, 0), 1, 1, color=color_dict[a]) for a in all_assets]
466+
ax.legend(handles, all_assets, title='Assets', bbox_to_anchor=(1.02, 1), loc='upper right')
467+
elif color_by == 'role':
468+
handles = [plt.Rectangle((0, 0), 1, 1, color=color_dict[a]) for a in all_roles]
469+
ax.legend(handles, all_roles, title='Roles', bbox_to_anchor=(1.02, 1), loc='upper right')
470+
471+
if start_at_zero:
472+
ax.set_xlim(0, self.tf + 1)
473+
# Create a grid and adjust layout
474+
# ax.grid(True)
475+
plt.tight_layout()
476+
return fig, ax
477+
478+
def chart(self, start_at_zero=True):
479+
'''Generate a chart grouped by asset showing when each asset is active across all actions.
480+
481+
Parameters
482+
----------
483+
start_at_zero : bool, optional
484+
If True, the x-axis starts at zero. Defaults to True.
485+
486+
Returns
487+
-------
488+
fig : matplotlib.figure.Figure
489+
The figure object containing the Gantt chart.
490+
ax : matplotlib.axes.Axes
491+
The axes object containing the Gantt chart.
492+
'''
493+
pass
494+

famodel/irma/vessels.yaml

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
# --- Anchor Handling Tug / Supply Vessel (AHTS / AHV) ---
44

55
AHTS_alpha:
6-
# Offshore Tug/Anchor Handling Tug Supply (AHTS) – Towing floating structures, handling and laying anchors/mooring lines, tensioning and positioning support.
6+
# Offshore Tug/Anchor Handling Tug Supply (AHTS) – Towing floating structures, handling and laying anchors/mooring lines, tensioning and positioning support.
7+
name: AHTS_alpha
78
type: AHTS
89
transport:
910
transit_speed_mps: 4.7
@@ -53,7 +54,8 @@ AHTS_alpha:
5354
# --- Multipurpose Support Vessel ---
5455

5556
MPSV_01:
56-
# Multi-Purpose Support Vessel (MSV) – Flexible vessel used for maintenance, diving, construction, or ROV tasks. Combines features of CSV, DSV and ROVSV.
57+
# Multi-Purpose Support Vessel (MSV) – Flexible vessel used for maintenance, diving, construction, or ROV tasks. Combines features of CSV, DSV and ROVSV.
58+
name: MPSV_01
5759
type: MSV
5860
transport:
5961
transit_speed_mps: 4.7
@@ -99,7 +101,8 @@ MPSV_01:
99101
# --- Construction Support Vessel ---
100102

101103
CSV_A:
102-
# Construction Support Vessel (CSV) – General-purpose vessel supporting subsea construction, cable lay and light installation. Equipped with cranes, moonpools and ROVs.
104+
# Construction Support Vessel (CSV) – General-purpose vessel supporting subsea construction, cable lay and light installation. Equipped with cranes, moonpools and ROVs.
105+
name: CSV_A
103106
type: CSV
104107
transport:
105108
transit_speed_mps: 4.7
@@ -151,7 +154,8 @@ CSV_A:
151154
# --- ROV Support Vessel ---
152155

153156
ROVSV_X:
154-
# ROV Support Vessel (ROVSV) – Dedicated to operating and supporting Remotely Operated Vehicles (ROVs) for inspection, survey or intervention.
157+
# ROV Support Vessel (ROVSV) – Dedicated to operating and supporting Remotely Operated Vehicles (ROVs) for inspection, survey or intervention.
158+
name: ROVSV_X
155159
type: ROVSV
156160
transport:
157161
transit_speed_mps: 6.7
@@ -186,7 +190,8 @@ ROVSV_X:
186190
# --- Diving Support Vessel ---
187191

188192
DSV_Moon:
189-
# Diving Support Vessel (DSV) – Specifically equipped to support saturation diving operations. Includes diving bells, decompression chambers and dynamic positioning.
193+
# Diving Support Vessel (DSV) – Specifically equipped to support saturation diving operations. Includes diving bells, decompression chambers and dynamic positioning.
194+
name: DSV_Moon
190195
type: DSV
191196
transport:
192197
transit_speed_mps: 4.7
@@ -213,7 +218,8 @@ DSV_Moon:
213218
# --- Heavy Lift Vessel ---
214219

215220
HL_Giant:
216-
# Heavy Lift Vessel (HL) – Used for transporting and installing very large components, like jackets, substations, or monopiles. Equipped with high-capacity cranes (>3000 t).
221+
# Heavy Lift Vessel (HL) – Used for transporting and installing very large components, like jackets, substations, or monopiles. Equipped with high-capacity cranes (>3000 t).
222+
name: HL_Giant
217223
type: HL
218224
transport:
219225
transit_speed_mps: 4.7
@@ -268,7 +274,8 @@ SURV_Swath:
268274
# --- Barge ---
269275

270276
Barge_squid:
271-
# Barge – non-propelled flat-top vessel used for transporting heavy equipment, components and materials. Requires towing or positioning support from tugs or AHTS vessels.
277+
# Barge – non-propelled flat-top vessel used for transporting heavy equipment, components and materials. Requires towing or positioning support from tugs or AHTS vessels.
278+
name: Barge_squid
272279
type: BARGE
273280
transport:
274281
transit_speed_mps: 2 # No self-propulsion

0 commit comments

Comments
 (0)