So I know there is a Date-Picker component, I know there is a Range-Slider as well, but I was wondering if someone had figured out how to make a “Date-Range-Slider” which could be used to filter a dataset between two datetime objects.
If anyone has something on this please let me know - thank you!
from dateutil.relativedelta import relativedelta
# Usual DASH stuff
dcc.RangeSlider(
id = 'datetime_RangeSlider',
updatemode = 'mouseup', #don't let it update till mouse released
min = unix_time_millis(d.datetime.min()),
max = unix_time_millis(d.datetime.max()),
value = [unix_time_millis(d.datetime.min()),
unix_time_millis(d.datetime.max())],
#TODO add markers for key dates
marks=get_marks_from_start_end(d.datetime.min(),
d.datetime.max()),
),
def get_marks_from_start_end(start, end):
''' Returns dict with one item per month
{1440080188.1900003: '2015-08',
'''
result = []
current = start
while current <= end:
result.append(current)
current += relativedelta(months=1)
return {unix_time_millis(m):(str(m.strftime('%Y-%m'))) for m in result}
The following code runs before the RangeSlider is called…
maxmarks=13
tday=pd.Timestamp.today() #gets timestamp of today
m1date=tday+DateOffset(months=-maxmarks+1) #first month on slider
datelist=pd.date_range(m1date, periods=maxmarks, freq='M') # list of months as dates
dlist=pd.DatetimeIndex(datelist).normalize()
tags={} #dictionary relating marks on slider to tags. tags are shown as "Apr', "May', etc
datevalues={} #dictionary relating mark to date value
x=1
for i in dlist:
tags[x]=(i+DateOffset(months=1)).strftime('%b') #gets the string representation of next month ex:'Apr'
datevalues[x]=i
x=x+1
include these libraries…
import pandas as pd
from pandas.tseries.offsets import *
The code I used:
dcc.RangeSlider(
id=‘my-range-slider’,
updatemode = ‘mouseup’,
min = unix_time_millis(downloads()[‘AUDITTIME’].min()),
max = unix_time_millis(downloads()[‘AUDITTIME’].max()),
step=None,
value = [unix_time_millis(downloads()[‘AUDITTIME’].min()),
unix_time_millis(downloads()[‘AUDITTIME’].max())],
marks=get_marks_from_start_end(downloads()[‘AUDITTIME’].min(),downloads()[‘AUDITTIME’].max())
)
Thanks for sharing the code. It works, except from that the label marks are not shown. So the dots are , but not the date itself. No errors shown and get_marks_from_start_end seems to have the expected output. Any ideas? thanks
In case it helps anyone - this approach seemed to work well with a Pandas DateTimeIndex:
import numpy as np
import pandas as pd
## --- Dash stuff ---
dcc.RangeSlider(
allowCross=False,
id="date-slider",
min=pd.Timestamp(df.index.min()).timestamp(),
max=pd.Timestamp(df.index.max()).timestamp(),
marks = get_marks(df),
)
def get_marks(df):
"""Convert DateTimeIndex to a dict that maps epoch to str
Parameters:
df (Pandas DataFrame): df with index of type DateTimeIndex
Returns:
dict: format is {
1270080000: '04-2010',
1235865600: '03-2009',
...etc.
}
"""
# extract unique month/year combinations as a PeriodIndex
months = df.index.to_period("M").unique()
# convert PeriodIndex to epoch series and MM-YYYY string series
epochs = months.to_timestamp().astype(np.int64) // 10**9
strings = months.strftime("%m-%Y")
return dict(zip(epochs, strings))