Skip to content

widgets

main.widgets ¤

Widgets to be used to interact with the plots.

Functions¤

add_bar_callback_to_button(button, dates, plot, chart_months) ¤

Add the JS callback to a button to update a plot x_range and picker dates.

'window.skip_bar_picker_callback = true' is used to prevent the callback in add_bar_callback_to_date_pickers from being run concurrently.

Parameters:

Name Type Description Default
button Button

The button to add the callback to

required
dates tuple[datetime, datetime]

Tuple of datetimes used to update the plot x_range

required
plot figure

The plot the button will be used to update

required
chart_months list[str]

list of months for x-axis in bar chart

required
Source code in main/widgets.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
def add_bar_callback_to_button(
    button: Button,
    dates: tuple[datetime, datetime],
    plot: figure,
    chart_months: list[str],
) -> None:
    """Add the JS callback to a button to update a plot x_range and picker dates.

    'window.skip_bar_picker_callback = true' is used to prevent the callback in
    add_bar_callback_to_date_pickers from being run concurrently.

    Args:
        button: The button to add the callback to
        dates: Tuple of datetimes used to update the plot x_range
        plot: The plot the button will be used to update
        chart_months: list of months for x-axis in bar chart
    """
    # Get formatted dates to use as x-range in plot
    start_tick = f"{dates[0].strftime('%b')} {dates[0].year}"
    end_tick = f"{dates[1].strftime('%b')} {dates[1].year}"

    start = chart_months.index(start_tick)
    end = chart_months.index(end_tick) + 1 if end_tick in chart_months else None
    indexed_months = chart_months[start:end]

    # JS code dictates what happens when the button is clicked
    button.js_on_click(
        CustomJS(
            args=dict(
                indexed_months=indexed_months,
                plot=plot,
            ),
            code="""window.skip_bar_picker_callback = true;
            plot.x_range.factors = indexed_months;""",
        )  # x_range in plot updated
    )

add_bar_callback_to_date_pickers(start_picker, end_picker, plot, chart_months) ¤

Add the JS callback to start and end date pickers to update a bar plot x_range.

As the x-range is categorical, we supply the list of formatted chart_months, index the list using the dates selected in the date pickers, and use the indexed list to update x_range.factors. '(window.skip_bar_picker_callback)' is used to prevent interference when the plot is updated using the buttons (otherwise when the buttons update the date pickers, this callback is also run).

Parameters:

Name Type Description Default
start_picker DatePicker

The start date picker to add the callback to

required
end_picker DatePicker

The end date picker to add the callback to

required
plot figure

The plot modified by the date pickers

required
chart_months list[str]

list of months for x-axis in bar chart

required
Source code in main/widgets.py
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
def add_bar_callback_to_date_pickers(
    start_picker: DatePicker,
    end_picker: DatePicker,
    plot: figure,
    chart_months: list[str],
) -> None:
    """Add the JS callback to start and end date pickers to update a bar plot x_range.

    As the x-range is categorical, we supply the list of formatted chart_months, index
    the list using the dates selected in the date pickers, and use the indexed list to
    update x_range.factors. '(window.skip_bar_picker_callback)' is used to prevent
    interference when the plot is updated using the buttons (otherwise when the buttons
    update the date pickers, this callback is also run).

    Args:
        start_picker: The start date picker to add the callback to
        end_picker: The end date picker to add the callback to
        plot: The plot modified by the date pickers
        chart_months: list of months for x-axis in bar chart
    """
    # JS code dictates what happens when a new date is selected on the pickers
    callback = CustomJS(
        args=dict(
            start_picker=start_picker,
            end_picker=end_picker,
            plot=plot,
            months=chart_months,
        ),
        code="""if (window.skip_bar_picker_callback) {
            window.skip_bar_picker_callback = false;
            return;
        }

        function getIndex(picker_value) {
            const date = new Date(picker_value);
            const month = date.toLocaleString('default', { month: 'short' });
            const year = date.getFullYear();
            const formatted_month = `${month} ${year}`;
            return months.indexOf(formatted_month);
        }

        const start_index = getIndex(start_picker.value);
        const end_index = getIndex(end_picker.value);
        const selected_months = months.slice(start_index, end_index + 1);

        plot.x_range.factors = selected_months;""",
    )  # x_range in the plot is updated with dates parsed from the date pickers

    start_picker.js_on_change("change", callback)
    end_picker.js_on_change("change", callback)

add_callback_to_button(button, dates, plot, start_picker, end_picker, include_future_dates=True) ¤

Add the JS callback to a button to update a plot x_range and picker dates.

If future dates are not included (e.g. for cost recovery plots), the end date of the x_range is the last day of the previous month.

Parameters:

Name Type Description Default
button Button

The button to add the callback to

required
dates tuple[datetime, datetime]

Tuple of datetimes used to update the plot x_range

required
plot figure

The plot the button will be used to update

required
start_picker DatePicker

The start date picker to update

required
end_picker DatePicker

The end date picker to update

required
include_future_dates bool

Whether to include future dates in the timeseries plot

True
Source code in main/widgets.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
def add_callback_to_button(
    button: Button,
    dates: tuple[datetime, datetime],
    plot: figure,
    start_picker: DatePicker,
    end_picker: DatePicker,
    include_future_dates: bool = True,
) -> None:
    """Add the JS callback to a button to update a plot x_range and picker dates.

    If future dates are not included (e.g. for cost recovery plots), the end date of
    the x_range is the last day of the previous month.

    Args:
        button: The button to add the callback to
        dates: Tuple of datetimes used to update the plot x_range
        plot: The plot the button will be used to update
        start_picker: The start date picker to update
        end_picker: The end date picker to update
        include_future_dates: Whether to include future dates in the timeseries plot
    """
    # JS code dictates what happens when the button is clicked
    end_date = (
        dates[1]
        if include_future_dates
        else (timezone.now()).replace(day=1) - timedelta(days=1)
    )

    button.js_on_click(
        CustomJS(
            args=dict(
                start=dates[0],
                end=end_date,
                # Picker values are set using date in isoformat
                start_isoformat=dates[0].isoformat().split("T")[0],
                end_isoformat=end_date.isoformat().split("T")[0],
                x_range=plot.x_range,
                start_picker=start_picker,
                end_picker=end_picker,
            ),
            code="""x_range.start = start;
            x_range.end = end;
            start_picker.value = start_isoformat;
            end_picker.value = end_isoformat;""",
        )  # x_range in plot and dates displayed in pickers are updated
    )

add_timeseries_callback_to_date_pickers(start_picker, end_picker, plot) ¤

Add the JS callback to start and end date pickers to update a plot x_range.

Parameters:

Name Type Description Default
start_picker DatePicker

The start date picker to add the callback to

required
end_picker DatePicker

The end date picker to add the callback to

required
plot figure

The plot modified by the date pickers

required
Source code in main/widgets.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
def add_timeseries_callback_to_date_pickers(
    start_picker: DatePicker, end_picker: DatePicker, plot: figure
) -> None:
    """Add the JS callback to start and end date pickers to update a plot x_range.

    Args:
        start_picker: The start date picker to add the callback to
        end_picker: The end date picker to add the callback to
        plot: The plot modified by the date pickers
    """
    # JS code dictates what happens when a new date is selected on the pickers
    callback = CustomJS(
        args=dict(
            start_picker=start_picker, end_picker=end_picker, x_range=plot.x_range
        ),
        code="""const start = Date.parse(start_picker.value);
            const end = Date.parse(end_picker.value);
            x_range.start = start
            x_range.end = end""",
    )  # x_range in the plot is updated with dates parsed from the date pickers
    start_picker.js_on_change("value", callback)
    end_picker.js_on_change("value", callback)

date_picker(title, default_date, min_date, max_date) ¤

Provides a Date Picker widget to select dates in the plots.

Parameters:

Name Type Description Default
title str

Title to display above the Date Picker.

required
default_date date

The initial date to display

required
min_date date

The earliest possible date the user can select

required
max_date date

The latest possible date the user can select

required

Returns:

Type Description
DatePicker

The initialised Date Picker widget.

Source code in main/widgets.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def date_picker(
    title: str, default_date: date, min_date: date, max_date: date
) -> DatePicker:
    """Provides a Date Picker widget to select dates in the plots.

    Args:
        title: Title to display above the Date Picker.
        default_date: The initial date to display
        min_date: The earliest possible date the user can select
        max_date: The latest possible date the user can select

    Returns:
        The initialised Date Picker widget.
    """
    picker = DatePicker(
        title=title,
        value=default_date,
        min_date=min_date,
        max_date=max_date,
    )
    return picker

get_plot_date_pickers(min_date, max_date, default_start, default_end) ¤

Get start and end date pickers for a timeseries plot.

Creates separate date pickers to choose the start and end date to use as the x_range for a plot. Both pickers are provided with a default date to display and minimum and maximum possible dates that the user can select.

Parameters:

Name Type Description Default
min_date date

The earliest possible date the user can select

required
max_date date

The latest possible date the user can select

required
default_start date

The default date to display in the start picker

required
default_end date

The default date to display in the end picker

required

Returns: A tuple of date pickers for selecting the start and end dates of

Source code in main/widgets.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
def get_plot_date_pickers(
    min_date: date,
    max_date: date,
    default_start: date,
    default_end: date,
) -> tuple[DatePicker, DatePicker]:
    """Get start and end date pickers for a timeseries plot.

    Creates separate date pickers to choose the start and end date to use as the x_range
    for a plot. Both pickers are provided with a default date to display and minimum
    and maximum possible dates that the user can select.

    Args:
        min_date: The earliest possible date the user can select
        max_date: The latest possible date the user can select
        default_start: The default date to display in the start picker
        default_end: The default date to display in the end picker

    Returns: A tuple of date pickers for selecting the start and end dates of

    """
    start_picker = date_picker(
        title="Select start date:",
        default_date=default_start,
        min_date=min_date,
        max_date=max_date,
    )
    end_picker = date_picker(
        title="Select end date:",
        default_date=default_end,
        min_date=min_date,
        max_date=max_date,
    )

    return start_picker, end_picker