11import marimo
22
3- __generated_with = "0.11.18 "
3+ __generated_with = "unknown "
44app = marimo .App (width = "medium" )
55
66
7+ @app .cell
8+ def _ (mo ):
9+ time_hrs_slider_ = mo .ui .slider (start = - 10 , stop = 10 , step = 0.5 )
10+ time_hrs_slider_
11+ return (time_hrs_slider_ ,)
12+
13+
714@app .cell (hide_code = True )
815def _ (cal , plot_calendar ):
916
1017 # Plot calendar
1118 fig = plot_calendar (cal )
12- return ( fig ,)
19+ return
1320
1421
1522@app .cell
@@ -27,7 +34,7 @@ def _():
2734@app .cell
2835def _ (pd ):
2936 from dataclasses import dataclass , field
30- from datetime import datetime , timedelta
37+ from datetime import datetime , timedelta , time
3138 from typing import Optional , Union , List
3239 import uuid
3340 import copy
@@ -105,51 +112,74 @@ def update_event(self,
105112 for e in targets :
106113 e .start = e .start + timedelta (seconds = delta_start )
107114 e .end = e .end + timedelta (seconds = delta_end )
108-
109- return (
110- Calendar ,
111- Event ,
112- List ,
113- Optional ,
114- Union ,
115- copy ,
116- dataclass ,
117- datetime ,
118- events_to_dataframe ,
119- field ,
120- timedelta ,
121- uuid ,
122- )
115+ return Calendar , Event , datetime , events_to_dataframe , time , timedelta
123116
124117
125118@app .cell
126119def _ (Calendar , events_to_dataframe ):
127120 import plotly .express as px
128121
129122 def plot_calendar (calendar : Calendar , show : bool = True ):
123+ """
124+ Plots the calendar events, attempting to use resource names as colors.
125+ Falls back to standard coloring if resource names are not valid colors.
126+ """
130127 df = events_to_dataframe (calendar .events )
131- fig = px .timeline (
132- df ,
133- x_start = "start" ,
134- x_end = "end" ,
135- y = "group" , # Grouped lanes on y-axis
136- color = "resource" , # Optional color-coding
137- hover_data = ["name" , "description" ]
138- )
139- fig .update_yaxes (autorange = "reversed" ) # Keep top-down order :contentReference[oaicite:6]{index=6}
140- # fig.update_xaxes(
141- # tickformat="%H:%M", # Hour:Minute format
142- # dtick=3600000 # One-hour intervals (ms) :contentReference[oaicite:7]{index=7}
143- # )
128+
129+ try :
130+ # --- Attempt 1: Use resource names as colors ---
131+
132+ # 1. Create the color map from unique resource names
133+ # This assumes resource names are valid color strings (e.g., "Red", "black", "blue")
134+ unique_resources = df ['resource' ].unique ()
135+ color_map = {res : res for res in unique_resources }
136+
137+ print ("Attempting to apply color palette from resource names..." )
138+
139+ # 2. Try to plot using this map for the 'color_discrete_map' argument
140+ # This line will fail if any name in 'color_map' is not a valid color.
141+ fig = px .timeline (
142+ df ,
143+ x_start = "start" ,
144+ x_end = "end" ,
145+ y = "group" ,
146+ color = "resource" ,
147+ color_discrete_map = color_map , # <-- This is the custom palette
148+ hover_data = ["name" , "description" ]
149+ )
150+ print ("Successfully applied custom color palette." )
151+
152+ except Exception as e :
153+ # --- Attempt 2: Fallback to standard coloring ---
154+
155+ print (f"\n --- PLOTTING WARNING ---" )
156+ print (f"Failed to apply custom palette from resource names. Error: { e } " )
157+ print ("This likely means a 'resource' name isn't a valid color (e.g., 'Incubator1' instead of 'red')." )
158+ print ("Falling back to standard Plotly coloring.\n " )
159+
160+ # Plot again, but without the 'color_discrete_map' argument
161+ fig = px .timeline (
162+ df ,
163+ x_start = "start" ,
164+ x_end = "end" ,
165+ y = "group" ,
166+ color = "resource" , # <-- Standard coloring
167+ hover_data = ["name" , "description" ]
168+ )
169+
170+ # --- Common layout updates ---
171+ fig .update_yaxes (autorange = "reversed" )
144172 fig .update_layout (title = "Linked Event Schedule" , xaxis_title = "Time" , yaxis_title = "Group" )
173+
145174 if show :
146175 fig .show ()
176+
147177 return fig
148- return plot_calendar , px
178+ return ( plot_calendar ,)
149179
150180
151181@app .cell
152- def _ (Calendar , Event , datetime , timedelta ):
182+ def _ (Calendar , Event , datetime , time , time_hrs_slider_ , timedelta ):
153183 # events = [
154184 # Event("1", "Opening Ceremony", datetime(2025,5,12,9,0), datetime(2025,5,12,10,0), resource="Main Hall"),
155185 # Event("2", "Keynote", datetime(2025,5,12,10,30),datetime(2025,5,18,11,30),resource="Main Hall"),
@@ -162,28 +192,52 @@ def _(Calendar, Event, datetime, timedelta):
162192
163193 # Initial events with a shared linkGroup "Team"
164194
165- dissection_time = datetime (2025 ,6 ,5 ,9 ,0 )
195+ dissection_time_ = datetime (2025 ,10 ,30 ,8 ,0 )
196+
197+ dissection_time = dissection_time_ - timedelta (hours = time_hrs_slider_ .value )
198+
166199
167200 events = [
168- # HH 10
169- Event ("Incub to hh8" , dissection_time - timedelta (hours = 9 ) - timedelta (hours = 2 ) - timedelta (hours = 30 ), timedelta (hours = 30 ), group = "HH10" , resource = "Blue" ),
170- Event ("Harvest & Epor" , dissection_time - timedelta (hours = 9 ) - timedelta (hours = 2 ), timedelta (hours = 2 ), group = "HH10" , resource = "Red" , linkGroup = "HH10" ),
171- Event ("Epor Incub" , dissection_time - timedelta (hours = 9 ), timedelta (hours = 9 ), group = "HH10" , resource = "Blue" , linkGroup = "HH10" ),
172- # HH 15
173- Event ("Incub to hh11" , dissection_time - timedelta (hours = 17 ) - timedelta (hours = 2 ) - timedelta (hours = 42 ), timedelta (hours = 42 ), group = "HH15" , resource = "Blue" , linkGroup = "HH15" ),
174- Event ("Harvest & Epor" , dissection_time - timedelta (hours = 17 ) - timedelta (hours = 2 ), timedelta (hours = 2 ), group = "HH15" , resource = "Red" , linkGroup = "HH15" ),
175- Event ("Epor Incub" , dissection_time - timedelta (hours = 17 ), timedelta (hours = 17 ), group = "HH15" , resource = "Blue" , linkGroup = "HH15" ),
201+ # # HH 10
202+ # Event("Incub to hh8", dissection_time - timedelta(hours=9) - timedelta(hours=2) - timedelta(hours=30), timedelta(hours=30), group="HH10", resource="Blue"),
203+ # Event("Harvest & Epor", dissection_time - timedelta(hours=9) - timedelta(hours=2), timedelta(hours=2), group="HH10", resource="Red", linkGroup="HH10"),
204+ # Event("Epor Incub", dissection_time - timedelta(hours=9), timedelta(hours=9), group="HH10", resource="Blue", linkGroup="HH10"),
205+ # # HH 15
206+ # Event("Incub to hh11", dissection_time - timedelta(hours=17) - timedelta(hours=2) - timedelta(hours=42), timedelta(hours=42), group="HH15", resource="Blue", linkGroup="HH15"),
207+ # Event("Harvest & Epor", dissection_time - timedelta(hours=17) - timedelta(hours=2), timedelta(hours=2), group="HH15", resource="Red", linkGroup="HH15"),
208+ # Event("Epor Incub", dissection_time - timedelta(hours=17), timedelta(hours=17), group="HH15", resource="Blue", linkGroup="HH15"),
176209 # HH 18
177210 Event ("Incub to hh11" , dissection_time - timedelta (hours = 34 ) - timedelta (hours = 2 ) - timedelta (hours = 42 ), timedelta (hours = 42 ), group = "HH18" , resource = "Blue" , linkGroup = "HH18" ),
178211 Event ("Harvest & Epor" , dissection_time - timedelta (hours = 34 ) - timedelta (hours = 2 ), timedelta (hours = 2 ), group = "HH18" , resource = "Red" , linkGroup = "HH18" ),
179212 Event ("Epor Incub" , dissection_time - timedelta (hours = 34 ), timedelta (hours = 34 ),group = "HH18" , resource = "Blue" , linkGroup = "HH18" ),
180213 # Dissect & Dissociate
181- Event ("Dissect" , dissection_time , timedelta (minutes = 45 ) ,group = "HH10" , resource = "Red" ),
182- Event ("Dissociate" , datetime (2025 ,6 ,5 ,10 ,30 ), timedelta (hours = 1.5 ), group = "HH10" , resource = "Red" ),
214+ Event ("Dissect" , dissection_time , timedelta (minutes = 45 ) ,group = "HH18" , resource = "Red" ),
215+ # Event("Dissociate", datetime(2025,6,5,10,30), timedelta(hours=1.5), group="HH10", resource="Red"),
216+
217+ ]
218+
219+
220+ ### Nights - Dead hours to avoid (Generated)
221+ # We define the start time (10 PM) and duration (8 hours)
222+ night_start_time = time (22 , 0 )
223+ night_duration = timedelta (hours = 8 )
224+
225+ # List comprehension to generate dead hours for 4 nights leading up to dissection
226+ # range(1, 5) will loop for i = 1, 2, 3, 4
227+ dead_hours = [
228+ Event (
229+ "Night" , # Event name
230+ datetime .combine (dissection_time_ .date () - timedelta (days = i ), night_start_time ), # Start time: 10 PM on the day i days before
231+ night_duration , # Duration: 8 hours (10 PM to 6 AM)
232+ group = "Dead" ,
233+ resource = "Black" ,
234+ linkGroup = "Dead"
235+ )
236+ for i in range (1 , 5 ) # Generates for 1, 2, 3, and 4 days prior
183237 ]
184238
185- cal = Calendar (events )
186- return cal , dissection_time , events
239+ cal = Calendar (events + dead_hours )
240+ return ( cal ,)
187241
188242
189243@app .cell
0 commit comments