= LightSchedule(100.0) constant_schedule
Lights
Overview
The Lights module streamlines the process of creating light schedules for circadian models. Its main class is LightSchedule
which facilitates creating light functions of time. LightSchedule
objects can be added, subtracted, and concatenated between each other to create custom light schedules.
Creation and visualization
Light schedules can be created by passing either a float
value or a function to the LightSchedule
constructor. For example, we can create a schedule of constant light by:
and plot it between 0 and 72 hours using the plot
method:
= constant_schedule.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)');
ax.set_ylabel(0.0, 120.0); ax.set_ylim(
If we want to create a schedule that varies over time, we can pass a function to the constructor:
def smooth_pulse_function(time):
= np.tanh((time - 7.0))
rise = np.tanh((time - 20.0))
fall = 100 * (rise - fall) / 2.0
y return y
= LightSchedule(smooth_pulse_function)
smooth_pulse = smooth_pulse.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
Additionally, the LightSchedule
constructor accepts a period
argument which allows us to specify the periodicity of the schedule. For example, we can make the smooth pulse repeat every 24 hours:
= LightSchedule(smooth_pulse_function, period=24.0)
smooth_pulse = smooth_pulse.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
Typically, we would like to create schedules that are composed of on-and-off pulses of light. We can do this via the LightSchedule.from_pulse()
function. For example, we can create a periodic schedule with 16 hours of light and 8 hours of darkness by:
= LightSchedule.from_pulse(100.0, start=8, duration=16.0, period=24.0)
on_off_schedule = on_off_schedule.plot(0.0, 72.0)
ax -5, 110);
ax.set_ylim('Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
see the API documentation for a description of the parameters that can be passed to LightSchedule.from_pulse()
, including adding a baseline to the pulse via baseline
.
The resulting LightSchedule
objects are callable and return the value of the schedule at the specified times
= np.linspace(0.0, 72.0, 10)
times print(on_off_schedule(times))
[ 0. 100. 100. 0. 100. 100. 0. 100. 100. 0.]
Addition and subtraction
LightSchedule
objects can be combined using the +
and -
operators. For example, we can add a pulse of light at 40 hours to our on_off_schedule
by:
= LightSchedule.from_pulse(20.0, start=40, duration=2.0)
single_pulse = on_off_schedule + single_pulse
combined_schedule = combined_schedule.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
or subtract it:
= on_off_schedule - single_pulse
combined_schedule = combined_schedule.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
Concatenation
LightSchedule
objects can be concatenated in time using the concatenate_at()
method. For example, we can create a schedule where the first 48 hours consist of 8 hours of darkness and 16 hours of light, but after that the schedule is constant at 50 lux:
= LightSchedule.from_pulse(100.0, start=8, duration=16.0, period=24.0)
regular_schedule = LightSchedule(50.0)
constant_light = regular_schedule.concatenate_at(constant_light, 48.0)
concatenated_schedule = concatenated_schedule.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
The approach works for all types of schedules. For example, we can concatenate smooth_pulse
to on_off_schedule
at 28 hours by:
= on_off_schedule.concatenate_at(smooth_pulse, 28.0)
on_off_to_smooth = on_off_to_smooth.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
It is important to note that the default behavior of schedule_1.concatenate_at(schedule_2, timepoint)
is to shift the time=0
of schedule_2
to timepoint
. This can be appreciated if we concatenate the same schedules as above, but with timepoint=40
:
= on_off_schedule.concatenate_at(smooth_pulse, 40.0)
on_off_to_smooth = on_off_to_smooth.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
we see that the second on-and-off pulse is suddenly interrupted by the beginning of the smoot pulse. This is because the time=0
of smooth_pulse
is shifted to timepoint=40
. If we want to concatenate the schedules without shifting the time=0
of schedule_2
(keep the time=0
of schedule_2
aligned with that of schedule_1
), we can pass shift=False
to the concatenate_at()
method:
= on_off_schedule.concatenate_at(smooth_pulse, 40.0, shift_schedule=False)
on_off_to_smooth = on_off_to_smooth.plot(0.0, 72.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)'); ax.set_ylabel(
Typical light schedules
The LightSchedule
class implements several helper functions to obtain common light schedules:
LightSchedule.Regular
: light of a typical dayLightSchedule.ShiftWork
: approximation of the usual light for shift workersLightSchedule.SlamShift
: light pattern that slam shift workers experience when changing shiftsLightSchedule.SocialJetlag
: light pattern experienced by staying up late on weekends
Check out the API documentation for a description of the parameters that can be passed to each function.
Regular light
LightSchedule.Regular
is a typical light schedule that repeats every 24 hours. The default schedule is 16 hours of light and 8 hours of darkness, but this can be changed by passing lights_on
and lights_off
to the constructor.
= LightSchedule.Regular()
regular_light = regular_light.plot(0.0, 24*7.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)');
ax.set_ylabel(16, 4);
ax.figure.set_size_inches(# add a vertical line to the start of each day in dashed gray
for day in range(8):
*24.0, color='gray', linestyle='--');
ax.axvline(day0, 24.0*8.0, 12));
ax.set_xticks(np.arange(0.0, 24.0*7.0); ax.set_xlim(
Shift worker
LightSchedule.ShiftWork
approximates what a typical light schedule looks for some shift workers. The schedule is periodic over a whole work week (determined by the sum of days_on
and days_off
) and implements transitions between workdays and days off. The default schedule is:
= LightSchedule.ShiftWork()
shift_schedule = shift_schedule.plot(0.0, 24.0*8.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)');
ax.set_ylabel(16, 4);
ax.figure.set_size_inches(# add a vertical line to the start of each day in dashed gray
for day in range(8):
*24.0, color='gray', linestyle='--');
ax.axvline(day0, 24.0*8.0, 12));
ax.set_xticks(np.arange(= 5
days_on = 2
days_off = 9.0
lights_off_workday = 17.0
lights_on_workday = lights_off_workday + 24*(days_on-1)
time_last_workday = lights_on_workday + 24.0*(days_on + days_off - 1)
time_last_day_off = time_last_day_off + lights_on_workday
time_first_workday # set background color to light red for the workdays
0.0, time_last_workday, facecolor='r', alpha=0.1, label='Workdays');
ax.axvspan(='r', alpha=0.1);
ax.axvspan(time_last_day_off, time_first_workday, facecolor# set background color to light green for days off
='g', alpha=0.1, label='Days off');
ax.axvspan(time_last_workday, time_last_day_off, facecolor# set limits to be a week
0.0, 24.0*7.0);
ax.set_xlim(# place legend at the top of the plot
='upper center', bbox_to_anchor=(0.5, 1.15), ncol=2); ax.legend(loc
Slam shift
LightSchedule.SlamShift
approximates the light schedule that slam shift workers experience when changing shifts. The schedule starts with before_days
where the worker is on a regular schedule and then shifts to a new schedule by shift
hours. Before the shift happens, there’s a transition via sleep banking. The default schedule is:
= LightSchedule.SlamShift()
slam_shift = slam_shift.plot(0.0, 24.0*12.0)
ax 'Time (hours)');
ax.set_xlabel('Light (lux)');
ax.set_ylabel(16, 4);
ax.figure.set_size_inches(# add a vertical line to the start of each day in dashed gray
for day in range(13):
*24.0, color='gray', linestyle='--');
ax.axvline(day0, 24.0*12.0, 12));
ax.set_xticks(np.arange(# set background color to light red for the days before the shift
0.0, 24.0*5, facecolor='r', alpha=0.1, label='Before shift');
ax.axvspan(# set background color to light green for days after the shift
24.0*5, 24.0*12.0, facecolor='g', alpha=0.1, label='After shift');
ax.axvspan(# place legend at the top of the plot
='upper center', bbox_to_anchor=(0.5, 1.15), ncol=2);
ax.legend(loc0.0, 24.0*12.0); ax.set_xlim(
API documentation
LightSchedule
LightSchedule (light:Callable[[float],float], period:float=None)
Helper class for creating light schedules
Type | Default | Details | |
---|---|---|---|
light | typing.Callable[[float], float] | function that takes in a time value and returns a float, if a float is passed, then the light function is a constant set to that lux value | |
period | float | None | period in hours, if None, then the light pulse is not repeated. Must be positive |
Returns | None |
LightSchedule.from_pulse
LightSchedule.from_pulse (lux:float, start:float, duration:float, period:float=None, baseline:float=0.0)
Define a light schedule with a single (or a repetitive) light pulse
Type | Default | Details | |
---|---|---|---|
lux | float | light intensity of the pulse in lux. Must be nonnegative | |
start | float | start time in hours | |
duration | float | duration in hours. Must be positive | |
period | float | None | period in hours, if None, then the light pulse is not repeated. Must be positive |
baseline | float | 0.0 | baseline intensity outside of the light pulse in lux. Must be nonnegative |
Returns | LightSchedule |
LightSchedule.concatenate_at
LightSchedule.concatenate_at (schedule:__main__.LightSchedule, timepoint:float, shift_schedule:bool=True)
Concatenate two LightSchedules at the provided timepoint. When shift_schedule=True
, schedule
is shifted in time by timepoint
. Not shifted otherwise
Type | Default | Details | |
---|---|---|---|
schedule | LightSchedule | another LightSchedule object | |
timepoint | float | timepoint (in hours) at which schedules are concatenated | |
shift_schedule | bool | True | if True, then the schedule is shifted by the timepoint value |
Returns | LightSchedule |
LightSchedule.plot
LightSchedule.plot (plot_start_time:float, plot_end_time:float, num_samples:int=10000, ax=None, *args, **kwargs)
Plot the light function between start_time
and end_time
with num_samples
samples. Accepts matplotlib
*args
and **kwargs
Type | Default | Details | |
---|---|---|---|
plot_start_time | float | start time of the plot in hours | |
plot_end_time | float | end time of the plot in hours | |
num_samples | int | 10000 | number of samples to plot |
ax | NoneType | None | matplotlib axis to plot on |
args | |||
kwargs | |||
Returns | Axes |
LightSchedule.Regular
LightSchedule.Regular (lux:float=150.0, lights_on:float=7.0, lights_off:float=23.0)
Create a regular light and darkness 24 hour schedule
Type | Default | Details | |
---|---|---|---|
lux | float | 150.0 | intensity of the light in lux |
lights_on | float | 7.0 | time of the day for lights to come on in hours |
lights_off | float | 23.0 | time of the day for lights to go off in hours |
Returns | LightSchedule |
LightSchedule.ShiftWork
LightSchedule.ShiftWork (lux:float=150.0, days_on:int=5, days_off:int=2, lights_on_workday:float=17.0, lights_off_workday:float=9.0, lights_on_day_off:float=9.0, lights_off_day_off:float=24.0)
Create a light schedule for a shift worker
Type | Default | Details | |
---|---|---|---|
lux | float | 150.0 | lux intensity of the light. Must be a nonnegative float or int |
days_on | int | 5 | number of days on the night shift. Must be a positive int |
days_off | int | 2 | number of days off shift. Must be a positive int |
lights_on_workday | float | 17.0 | hour of the day for lights to come on on a workday. Must be between 0.0 and 24.0 |
lights_off_workday | float | 9.0 | hour of the day for lights to go off on a workday. Must be between 0.0 and 24.0 |
lights_on_day_off | float | 9.0 | hour of the day for lights to come on on a day off. Must be between 0.0 and 24.0 |
lights_off_day_off | float | 24.0 | hour of the day for lights to go off on a day off. Must be between 0.0 and 24.0 |
Returns | LightSchedule |
LightSchedule.SlamShift
LightSchedule.SlamShift (lux:float=150.0, shift:float=8.0, before_days:int=5, starting_lights_on:float=7.0, starting_lights_off:float=23.0)
Create a light schedule for a shift worker under a slam shift
Type | Default | Details | |
---|---|---|---|
lux | float | 150.0 | intensity of the light in lux |
shift | float | 8.0 | shift in the light schedule in hours |
before_days | int | 5 | days before the shift occurs |
starting_lights_on | float | 7.0 | time of the day for lights to come on |
starting_lights_off | float | 23.0 | time of the day for lights to go off |
Returns | LightSchedule |
Social jet lag
LightSchedule.SocialJetlag
implements a light schedule where the person stays up late on weekends while maintaining a regular schedule during the week. The schedule is periodic over the sum ofnum_regular_days
andnum_jetlag_days
.