You are right.
I just understood how the value argument works.
st.date_input( value=… )
Before, I thought I had to provide the range previously chosen by the user, in order to have that visible when using the widget. This was the cause of my headache!
I just realized that the value parameter doesn’t play any role once the user has already made once a choice. It is just a value to be used until the user makes a choice. The widget caches the user choice. If I don’t care, it is easy.
I am back again because I am still stuck in this problem.
I though I had solved it by doing this in the script that populates the sidebar (of any page):
dr = st.date_input("drr, value=allDates, min_value=allDates[0], max_value=allDates[1])
This works nicely for any of the pages of my multipage app.
However, changes to the daterange (dr) on one page doesn’t reflect when another page is activated.
Then the user needs to re-define the daterange (dr) everytimes he looks at another page.
Which is not very user-friendly.
Therefore, I wished to solve this issue by storing the datarange (dr) in the session_state and use it as initial value in the statement above.
I transformed the above statement as follows:
dr = st.date_input("drr, value=dr, min_value=allDates[0], max_value=allDates[1])
And this where my headache came back, exactly as before!
Even staying on one page, it becomes impossible to properly specify a range of date.
Typically it ends up with a 1 day daterange like
This why I wanted to control what happens when the widget state evolves.
I don’t know how to solve that.
I don’t know how have one single sidebar in a multipage app, while keep the st.date_input “synchronized” between pages.
This what I did.
I indeed stored dr in session_state.
I did not show in the my answer that dr is first retrieved from session_state.
When switching from one page to another, the state for the date_input is maintained.
But the problem is that it is impossible to define a range properly.
It always ends up with start and end date being the same.
I can guess more or less what happens, but I cannot solve it.
When the user clicks the start date, the dr tuple contains only one item.
The date_input widget is then initialized with a one element widget.
When the user clicks the end date, then de dr tuple contains twice the start date. Not clear why.
I am not sure I understand you. If I select 2024-2-13 and 2024-2-17 in the date picker, then I get (datetime.date(2024, 2, 13), datetime.date(2024, 2, 17)) as the return value. Anything else would be a bug.
When the user clicks the start date, the dr tuple contains only one item.
That is correct.
The date_input widget is then initialized with a one element widget.
When the user clicks the end date, then de dr tuple contains twice the start date. Not clear why.
This shouldn’t happen and certainly doesn’t happen for me.
A slight change to the example from the documentation suited my needs.
Below is the modified example.
I need to keep the same date range in the sidebar for all the pages of my app.
But a change to the date range needs to be taken into account only
when st.date_input really returns a range. Otherwise, the app should wait next iteration.
This tiny thing was the reason of my headache!
Probably because it was entangled with the rest of the logic, other parameters that may need to trigger some calculations.
I still have to get used to the Streamlit’s execution model !
Thanks again, you helped a lot!
Michel
PS:
By the way, if the app execution was delayed untils the date_input actually returned a range (as specified in the initial value), I would even not have had to care!
Would it be difficult to create a date_range_input widget, or the like?
But adding “if len(d)==2:” was not too difficult !!!
Modified example for a date range using st.date_input
import streamlit as st
from datetime import date
jan_1, dec_31 = (date(2023, 1, 1), date(2023, 12, 31))
jan_rg = (date(2023, 1, 13), date(2023, 1, 17))
if st.session_state:
d = st.session_state.d
else:
d = jan_rg
d = st.date_input("Select a range", value=d, min_value=jan_1, max_value=dec_31)
if len(d)==2:
st.session_state.d = d
d
But there are legitimate use cases where having 1 or 0 values is meaningful. It is up to the app to decide what values have a meaning and what to do with values that don’t.
Just had the idea that using on_change could help.
Would it be possible to use the callback to practically have date_input behaving exactly as a date_range_input widget?
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.