From 8b56f2b61e121bbd524b118a0e1b5575dc6f9bb8 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 23 May 2022 16:17:56 +0200 Subject: [PATCH 1/2] Add DatetimeRangeSlider --- .../reference/widgets/DateRangeSlider.ipynb | 3 +- .../widgets/DatetimeRangeSlider.ipynb | 111 ++++++++++++++++++ panel/widgets/__init__.py | 9 +- panel/widgets/slider.py | 31 +++++ 4 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 examples/reference/widgets/DatetimeRangeSlider.ipynb diff --git a/examples/reference/widgets/DateRangeSlider.ipynb b/examples/reference/widgets/DateRangeSlider.ipynb index 4a23138f9d..8c43c147ea 100644 --- a/examples/reference/widgets/DateRangeSlider.ipynb +++ b/examples/reference/widgets/DateRangeSlider.ipynb @@ -29,6 +29,7 @@ "\n", "* **``start``** (datetime): The range's lower bound\n", "* **``end``** (datetime): The range's upper bound\n", + "* **``step``** (int): Step in milliseconds\n", "* **``value``** (tuple): Tuple of upper and lower bounds of the selected range expressed as datetime types\n", "* **``value_throttled``** (tuple): Tuple of upper and lower bounds of the selected range expressed as datetime types throttled until mouseup\n", "\n", @@ -57,7 +58,7 @@ "date_range_slider = pn.widgets.DateRangeSlider(\n", " name='Date Range Slider',\n", " start=dt.datetime(2017, 1, 1), end=dt.datetime(2019, 1, 1),\n", - " value=(dt.datetime(2017, 1, 1), dt.datetime(2018, 1, 10))\n", + " value=(dt.datetime(2017, 1, 1), dt.datetime(2018, 1, 10)),\n", ")\n", "\n", "date_range_slider" diff --git a/examples/reference/widgets/DatetimeRangeSlider.ipynb b/examples/reference/widgets/DatetimeRangeSlider.ipynb new file mode 100644 index 0000000000..6cf8d6f12c --- /dev/null +++ b/examples/reference/widgets/DatetimeRangeSlider.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import datetime as dt\n", + "import panel as pn\n", + "\n", + "pn.extension()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ``DateRangeSlider`` widget allows selecting a date range using a slider with two handles.\n", + "\n", + "For more information about listening to widget events and laying out widgets refer to the [widgets user guide](../../user_guide/Widgets.ipynb). Alternatively you can learn how to build GUIs by declaring parameters independently of any specific widgets in the [param user guide](../../user_guide/Param.ipynb). To express interactivity entirely using Javascript without the need for a Python server take a look at the [links user guide](../../user_guide/Param.ipynb).\n", + "\n", + "#### Parameters:\n", + "\n", + "For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n", + "\n", + "\n", + "##### Core\n", + "\n", + "* **``start``** (datetime): The range's lower bound\n", + "* **``end``** (datetime): The range's upper bound\n", + "* **``step``** (int): Step in milliseconds\n", + "* **``value``** (tuple): Tuple of upper and lower bounds of the selected range expressed as datetime types\n", + "* **``value_throttled``** (tuple): Tuple of upper and lower bounds of the selected range expressed as datetime types throttled until mouseup\n", + "\n", + "##### Display\n", + "\n", + "* **``bar_color``** (color): Color of the slider bar as a hexadecimal RGB value\n", + "* **``callback_policy``** (str, **DEPRECATED**): Policy to determine when slider events are triggered (one of 'continuous', 'throttle', 'mouseup')\n", + "* **``callback_throttle``** (int): Number of milliseconds to pause between callback calls as the slider is moved\n", + "* **``direction``** (str): Whether the slider should go from left to right ('ltr') or right to left ('rtl')\n", + "* **``disabled``** (boolean): Whether the widget is editable\n", + "* **``name``** (str): The title of the widget\n", + "* **``orientation``** (str): Whether the slider should be displayed in a 'horizontal' or 'vertical' orientation.\n", + "* **``tooltips``** (boolean): Whether to display tooltips on the slider handle\n", + "\n", + "___\n", + "\n", + "The slider start and end can be adjusted by dragging the handles and whole range can be shifted by dragging the selected range." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "datetime_range_slider = pn.widgets.DatetimeRangeSlider(\n", + " name='Datetime Range Slider',\n", + " start=dt.datetime(2017, 1, 1), end=dt.datetime(2019, 1, 1),\n", + " value=(dt.datetime(2017, 1, 1), dt.datetime(2018, 1, 10)),\n", + " step=10000\n", + ")\n", + "\n", + "datetime_range_slider" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``DatetimeRangeSlider.value`` returns a tuple of datetime values that can be read out and set like other widgets:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "datetime_range_slider.value" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Controls\n", + "\n", + "The `DatetimeRangeSlider` widget exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pn.Row(datetime_range_slider.controls(jslink=True), datetime_range_slider)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/panel/widgets/__init__.py b/panel/widgets/__init__.py index 652c0f2b3d..538c668b52 100644 --- a/panel/widgets/__init__.py +++ b/panel/widgets/__init__.py @@ -70,9 +70,9 @@ from .misc import FileDownload, JSONEditor, VideoStream # noqa from .player import DiscretePlayer, Player # noqa from .slider import ( # noqa - DateSlider, DateRangeSlider, DiscreteSlider, EditableRangeSlider, - EditableFloatSlider, EditableIntSlider, FloatSlider, IntSlider, - IntRangeSlider, RangeSlider + DateSlider, DateRangeSlider, DatetimeRangeSlider, DiscreteSlider, + EditableRangeSlider, EditableFloatSlider, EditableIntSlider, + FloatSlider, IntSlider, IntRangeSlider, RangeSlider ) from .select import ( # noqa AutocompleteInput, CheckBoxGroup, CheckButtonGroup, CrossSelector, @@ -84,7 +84,7 @@ from .terminal import Terminal # noqa from .debugger import Debugger # noqa from .text_to_speech import TextToSpeech, Utterance, Voice # noqa -from .texteditor import TextEditor# noqa +from .texteditor import TextEditor # noqa __all__ = ( "Ace", @@ -101,6 +101,7 @@ "DataFrame", "DatePicker", "DateRangeSlider", + "DatetimeRangeSlider", "DateSlider", "DatetimeInput", "DatetimePicker", diff --git a/panel/widgets/slider.py b/panel/widgets/slider.py index c4d8a19577..b13e4dff2f 100644 --- a/panel/widgets/slider.py +++ b/panel/widgets/slider.py @@ -676,6 +676,37 @@ def _process_property_change(self, msg): return msg + +class DatetimeRangeSlider(DateRangeSlider): + + """ + The DatetimeRangeSlider widget allows selecting a datetime range + using a slider with two handles. Supports datetime.datetime and + np.datetime64 ranges. + + Reference: https://panel.holoviz.org/reference/widgets/DatetimeRangeSlider.html + + :Example: + + >>> import datetime as dt + >>> DatetimeRangeSlider( + ... value=(dt.datetime(2025, 1, 9), dt.datetime(2025, 1, 16)), + ... start=dt.datetime(2025, 1, 1), + ... end=dt.datetime(2025, 1, 31), + ... step=10000, + ... name="A tuple of datetimes" + ... ) + """ + + @property + def _widget_type(self): + try: + from bokeh.models import DatetimeRangeSlider + except Exception: + raise ValueError("DatetimeRangeSlider requires bokeh >= 2.4.3") + return DatetimeRangeSlider + + class _EditableContinuousSlider(CompositeWidget): """ The EditableFloatSlider extends the FloatSlider by adding a text From d13e7183f1a7f0be35e4c2f6ef7cce3a82b000a7 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Mon, 23 May 2022 16:32:57 +0200 Subject: [PATCH 2/2] Add CHANGELOG entry --- CHANGELOG.md | 3 ++- doc/releases.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6eb579af32..98b85e514d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,10 @@ Date: 2022-05-20 - Add repr to cell and edit events ([#3434](https://github.com/holoviz/panel/pull/3534)) - Improvements for pyodide handling ([#3444](https://github.com/holoviz/panel/pull/3444), [#3508](https://github.com/holoviz/panel/pull/3508), [#3511](https://github.com/holoviz/panel/pull/3511)) -- Add support for Plotly animation frames ([#3449](https://github.com/holoviz/panel/pull/3499)) +- Add support for `Plotly` animation frames ([#3449](https://github.com/holoviz/panel/pull/3499)) - Implement single and multi-selection in Vega pane ([#3470](https://github.com/holoviz/panel/pull/3470), [#3499](https://github.com/holoviz/panel/pull/3499), [#3505](https://github.com/holoviz/panel/pull/3505)) - Add typehints to help developers and users ([#3476](https://github.com/holoviz/panel/pull/3476)) +- Add `DatetimeRangeSlider` widget ([#3548](https://github.com/holoviz/panel/pull/3548)) ### Bug fixes diff --git a/doc/releases.md b/doc/releases.md index 1c9ba85542..dc115db43a 100644 --- a/doc/releases.md +++ b/doc/releases.md @@ -13,6 +13,7 @@ Date: 2022-05-20 - Add support for Plotly animation frames ([#3449](https://github.com/holoviz/panel/pull/3499)) - Implement single and multi-selection in Vega pane ([#3470](https://github.com/holoviz/panel/pull/3470), [#3499](https://github.com/holoviz/panel/pull/3499), [#3505](https://github.com/holoviz/panel/pull/3505)) - Add typehints to help developers and users ([#3476](https://github.com/holoviz/panel/pull/3476)) +- Add `DatetimeRangeSlider` widget ([#3548](https://github.com/holoviz/panel/pull/3548)) ### Bug fixes