iPyWidget - DatePicker interact with SelectionRangeSlider problem

Viewed 730

I'm trying to interact DatePicker with SelectionRangeSlider widgets. So far I could manage to link the slider with the DatePicker, but I'm getting trouble with the opposite way.

With this code the period slider updates the DatePicker:

from datetime import datetime
import pandas as pd
import ipywidgets as widgets

start_date = datetime(2021, 7, 1)
end_date = datetime(2021, 7, 5)

dates = pd.date_range(start_date, end_date, freq='D')

options = [(date.strftime(' %d %b %Y '), date) for date in dates]

pick_start = widgets.DatePicker(
    description='',
    disabled=False,
    value = start_date
)
pick_end = start_day = widgets.DatePicker(
    description='',
    disabled=False,
    value=end_date
)

selection_range_slider = widgets.SelectionRangeSlider(
    options=options,
    index=(0, len(options) - 1),
    description='Period',
    orientation='horizontal',
    layout=widgets.Layout(width='100%', padding='35px')
)


def update_pick(*args):
    pick_start.value = datetime.strptime(selection_range_slider.value[0].strftime("%Y-%m-%d"), "%Y-%m-%d")
    pick_end.value = datetime.strptime(selection_range_slider.value[1].strftime("%Y-%m-%d"), "%Y-%m-%d")

def update_slider(*args):
    selection_range_slider.value[0] =  pick_start.value.strftime("%Y-%m-%d")
    selection_range_slider.value[1] =  pick_end.value.strftime("%Y-%m-%d")

selection_range_slider.observe(update_pick, 'value')
pick_start.observe(update_slider, 'value')
pick_end.observe(update_slider, 'value')

center_layout = widgets.Layout(display='flex',
                                       align_items='center',
                                       width='100%')

day = widgets.HBox(children=[pick_start, selection_range_slider, pick_end], layout=center_layout)

display(day)

Also try with this function without result:

def update_slider(*args):
    start_date = datetime(pick_start.value.year, pick_start.value.month, pick_start.value.day)
    end_date = datetime(pick_end.value.year, pick_end.value.month, pick_end.value.day)

    dates = pd.date_range(start_date, end_date, freq='D')

    options = [(date.strftime(' %d %b %Y '), date) for date in dates]
    
    selection_range_slider.value[0] =  options[0]
    selection_range_slider.value[1] =  options[len(options)-1]

Need help interacting DatePicker with SelectionRangeSlider

Thanks!

1 Answers

you have done a nice job of creating a standalone question here, thanks. A couple suggestions for your next Q to speed up an answer.

  1. Please include your imports, I can't run your code without them:
from datetime import datetime
import pandas as pd
import ipywidgets as widgets
  1. Please post any error messages that you see when your code runs. I got a ValueError which would have improved the question even more.

The error said there was an issue assigning to an index of a tuple, Here's my solution.

  • Assign the whole tuple directly, you cannot update index 0 and then index 1 of your selection_range_slider

  • Use raw datetimes to pass between widgets, your mixed string conversions were causing some issues. You can still change how the dates are displayed in the slider by using a dictionary for options.

from datetime import datetime
import pandas as pd
import ipywidgets as widgets

start_date = datetime(2021, 7, 1)
end_date = datetime(2021, 7, 5)

dates = pd.date_range(start_date, end_date, freq='D')

options = {date.strftime(' %d %b %Y '): date for date in dates}

pick_start = widgets.DatePicker(
    description='',
    disabled=False,
    value = start_date
)
pick_end = start_day = widgets.DatePicker(
    description='',
    disabled=False,
    value=end_date
)

selection_range_slider = widgets.SelectionRangeSlider(
    options=options,
    index=(0, len(options) - 1),
    description='Period',
    orientation='horizontal',
    layout=widgets.Layout(width='100%', padding='35px')
)


def update_pick(*args):
    pick_start.value = selection_range_slider.value[0]
    pick_end.value = selection_range_slider.value[1]

def update_slider(*args):
    selection_range_slider.value =  (pick_start.value, pick_end.value)

selection_range_slider.observe(update_pick, 'value')
pick_start.observe(update_slider, 'value')
pick_end.observe(update_slider, 'value')

center_layout = widgets.Layout(display='flex',
                                       align_items='center',
                                       width='100%')

day = widgets.HBox(children=[pick_start, selection_range_slider, pick_end], layout=center_layout)

display(day)
Related