Python, Bokeh: cómo cambiar el rango del eje de fecha y hora

Me gustaría establecer el rango de un eje de fecha y hora utilizando un botón. Sin embargo, el comando

f.x_range = Range1d(start=start_date, end=end_date) 

no funciona Al hacer clic en el botón no pasa nada. No recibo ningún error, ni en las ventanas de terminal que ejecutan el servidor Bokeh, ni en la salida de la consola de mi navegador web Chrome.

Encuentra el código completo a continuación. Estoy agradecido por cualquier consejo.

Gracias,

Julian

     # Import libraries from bokeh.io import curdoc from bokeh.models import ColumnDataSource, DatetimeTickFormatter, Select, Range1d from bokeh.models.widgets import Button from bokeh.layouts import layout from bokeh.plotting import figure from datetime import datetime, timedelta from math import radians # Create figure f=figure(x_axis_type='datetime') # Create sample datetime data date_time = [datetime(2017,1,1) + timedelta(days=x) for x in range(0,365)] # Create ColumnDataSource source = ColumnDataSource(dict(datetime=date_time,parameter=range(0,365))) # Create Line f.line(x='datetime',y='parameter',color='olive',line_color='black',source=source) # Update xaxis function def update_xaxis(): start_date = datetime(year=int(select_start_year.value), month=int(select_start_month.value), day=int(select_start_day.value)) end_date = datetime(year=int(select_end_year.value), month=int(select_end_month.value), day=int(select_end_day.value)) f.x_range = Range1d(start=start_date, end=end_date) # Set date format for x axis f.xaxis.formatter=DatetimeTickFormatter(formats=dict( seconds=["%Y-%m-%d %H:%M:%S"], minsec=["%Y-%m-%d %H:%M:%S"], minutes=["%Y-%m-%d %H:%M:%S"], hourmin=["%Y-%m-%d %H:%M:%S"], hours=["%Y-%m-%d %H:%M:%S"], days=["%Y-%m-%d %H:%M:%S"], months=["%Y-%m-%d %H:%M:%S"], years=["%Y-%m-%d %H:%M:%S"], )) f.xaxis.major_label_orientation=radians(90) # Create Select and Button widgets options=[("2015","2015"),("2016","2016"),("2017","2017")] select_start_year=Select(title="Start Year",value="2017",options=options) options=[("01","01"),("02","02"),("03","03"),("04","04"),("05","05"),("06","06"),("07","07"),("08","08"),("09","09"),("10","10"),("11","11"),("12","12")] select_start_month=Select(title="Start Month",value="01",options=options) options=[("01","01"),("02","02"),("03","03"),("04","04"),("05","05"),("06","06"),("07","07"),("08","08"),("09","09"),("10","10"),("11","11"),("12","12"),("13","13"),("14","14"),("15","15"),("16","16"),("17","17"),("18","18"),("19","19"),("20","20"),("21","21"),("22","22"),("23","23"),("24","25"),("25","26"),("27","27"),("28","28"),("29","29"),("30","30"),("31","31")] select_start_day=Select(title="Start Day",value="01",options=options) options=[("2015","2015"),("2016","2016"),("2017","2017")] select_end_year=Select(title="End Year",value="2017",options=options) options=[("01","01"),("02","02"),("03","03"),("04","04"),("05","05"),("06","06"),("07","07"),("08","08"),("09","09"),("10","10"),("11","11"),("12","12")] select_end_month=Select(title="End Month",value="06",options=options) options=[("01","01"),("02","02"),("03","03"),("04","04"),("05","05"),("06","06"),("07","07"),("08","08"),("09","09"),("10","10"),("11","11"),("12","12"),("13","13"),("14","14"),("15","15"),("16","16"),("17","17"),("18","18"),("19","19"),("20","20"),("21","21"),("22","22"),("23","23"),("24","25"),("25","26"),("27","27"),("28","28"),("29","29"),("30","30"),("31","31")] select_end_day=Select(title="End Day",value="01",options=options) button = Button(label='Set Date') # Update x axis range on click button.on_click(update_xaxis) # Add elements to curdoc lay_out=layout([[f],[select_start_year],[select_start_month],[select_start_day],[select_end_year],[select_end_month],[select_end_day],[button]]) curdoc().add_root(lay_out) 

    Me di cuenta de la solución. En primer lugar, utilicé el widget Datepicker, que es mucho más elegante que los tres widgets Select. Luego, debe convertir el valor de fecha y hora del Selector de fecha en un valor flotante / entero, que representa los segundos transcurridos entre una fecha de referencia, es decir, el 1 de enero de 1970. Unix lo calcula en segundos, Java Script necesita este valor en milisegundos, por lo tanto La multiplicación por 1000. Aquí está el código:

     # Import libraries from bokeh.io import curdoc from bokeh.models import ColumnDataSource, DatetimeTickFormatter, DatePicker from bokeh.models.widgets import Button from bokeh.layouts import layout, column, row from bokeh.plotting import figure from datetime import datetime, timedelta from math import radians # Create figure f=figure(x_axis_type='datetime') # Create sample datetime data date_time = [datetime(2017,1,1) + timedelta(days=x) for x in range(0,365)] # Create ColumnDataSource source = ColumnDataSource(dict(datetime=date_time,parameter=range(0,365))) # Create Line f.line(x='datetime',y='parameter',color='olive',line_color='black',source=source) # Update xaxis function def update_xaxis(): # Calculate time delta from reference time in seconds timestamp_start = (datetime.combine(datepicker_start.value, datetime.min.time()) - datetime(1970, 1, 1)) / timedelta(seconds=1) timestamp_end = (datetime.combine(datepicker_end.value, datetime.min.time()) - datetime(1970, 1, 1)) / timedelta(seconds=1) f.x_range.start = int(timestamp_start)*1e3 # Multiply by 1e3 as JS timestamp is in milliseconds f.x_range.end = int(timestamp_end)*1e3 # Multiply by 1e3 as JS timestamp is in milliseconds # Set date format for x axis f.xaxis.formatter=DatetimeTickFormatter(formats=dict( seconds=["%Y-%m-%d %H:%M:%S"], minsec=["%Y-%m-%d %H:%M:%S"], minutes=["%Y-%m-%d %H:%M:%S"], hourmin=["%Y-%m-%d %H:%M:%S"], hours=["%Y-%m-%d %H:%M:%S"], days=["%Y-%m-%d %H:%M:%S"], months=["%Y-%m-%d %H:%M:%S"], years=["%Y-%m-%d %H:%M:%S"], )) f.xaxis.major_label_orientation=radians(90) # Create Datepicker and Button widgets datepicker_start = DatePicker(title='Start Date') datepicker_end = DatePicker(title='End Date') button = Button(label='Set Date') # Update x axis range on click button.on_click(update_xaxis) # Add elements to curdoc lay_out=layout([[row(f, column(button, row(datepicker_start,datepicker_end)))]]) curdoc().add_root(lay_out)