How do I set language of datetime axis in bokeh?
Asked Answered
Q

1

7

I have trouble with setting language in which datetime axis is formatted in bokeh. According to documentation, DatetimeTickFormatter produces time ticks 'according to the current locale'. However, whatever locale I set in Python, I get a plot formatted in English:

# jupyter notebook
import locale
locale.setlocale(locale.LC_ALL, 'pl')

import random
from datetime import datetime, date
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models.formatters import DatetimeTickFormatter

output_notebook()

x_values = [datetime(2018, i, 1) for i in range(6, 13)]
y_values = [random.normalvariate(0, 1) for i in range(6, 13)]

p = figure(plot_width=600, plot_height=300, 
           x_axis_type='datetime', title="test", 
           x_axis_label='x test', y_axis_label='y test')

p.line(
    x=x_values, 
    y=y_values
)

p.xaxis.formatter = DatetimeTickFormatter(months = '%B')

show(p)

enter image description here

If that's relevant, global system locale is set to en-US:

PS C:\Users\ppatrzyk> GET-WinSystemLocale

LCID             Name             DisplayName
----             ----             -----------
1033             en-US            English (United States)

I am working with plots in multiple languages so I need to change locale on the fly. Doing that through locale.setlocale has worked fine for me with both printing dates to console and with matplotlib. How can I set it in bokeh such that dates are formatted correctly?

EDIT:

The best workaround I got is to plot dates as numeric axis (unix timestamp) and then use major_label_overrides to replace ticks with correctly formatted dates obtained from python's datetime.strftime(). However, in this case zooming to ticks in between data points is broken, so this is far from being a satisfactory solution:

x_values = [datetime(2018, i, 1) for i in range(6, 13)]
y_values = [random.normalvariate(0, 1) for i in range(6, 13)]

x_values_timestamp = [int(el.timestamp()) for el in x_values]
x_values_labels = [el.strftime('%B') for el in x_values]

p = figure(plot_width=600, plot_height=300, title="test", 
           x_axis_label='x test', y_axis_label='y test')

p.xaxis.ticker = x_values_timestamp
p.xaxis.major_label_overrides = dict(zip(x_values_timestamp, x_values_labels))

p.line(
    x=x_values_timestamp, 
    y=y_values
)

show(p)

enter image description here

Quarterly answered 8/10, 2018 at 9:54 Comment(0)
B
1

I faced the same problem as I wanted the dates be displayed in portuguese of Portugal (pt-PT).

I found out that bokeh uses the file https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js to set the datetime language.

In my case, I wanted to generate standalone .html files, so I opted to set mode = 'inline' when exporting the file (output_file('test.html', mode = 'inline')) to embed the .js into the .html. But I assume that it should be possible to make the .html file load a custom bokeh-2.4.2.min.js by changing its path in the.html <head></head>.

To solve my problem, I edited the exported .html (edit the custom .js if you don't choose mode = 'inline') and replaced the following strings:

find = 'locale:"en_US"'
replace = 'locale:"pt_PT"'

find = 'en_US:{date:"%m/%d/%Y",time24:"%I:%M:%S %p",time12:"%I:%M:%S %p",dateTime:"%a %d %b %Y %I:%M:%S %p %Z",meridiem:["AM","PM"],month:{abbrev:"Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec".split("|"),full:"January|February|March|April|May|June|July|August|September|October|November|December".split("|")},day:{abbrev:"Sun|Mon|Tue|Wed|Thu|Fri|Sat".split("|"),full:"Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday".split("|")}}'
replace = 'pt_PT:{date:"%d/%m/%Y",time24:"%H:%M:%S",time12:"%I:%M:%S %p",dateTime:"%a %d %b %Y %H:%M:%S %Z",meridiem:["AM","PM"],month:{abbrev:"Jan|Fev|Mar|Abr|Mai|Jun|Jul|Ago|Set|Out|Nov|Dez".split("|"),full:"Janeiro|Fevereiro|Março|Abril|Maio|Junho|Julho|Agosto|Setembro|Outubro|Novembro|Dezembro".split("|")},day:{abbrev:"Dom|Seg|Ter|Qua|Qui|Sex|Sáb".split("|"),full:"Domingo|Segunda-feira|Terça-feira|Quarta-feira|Quinta-feira|Sexta-feira|Sábado".split("|")}}'

find = 'u="Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|year|month|day|hour|minute|second|millisecond"'
replace = 'u="Domingo|Segunda-feira|Terça-feira|Quarta-feira|Quinta-feira|Sexta-feira|Sábado|ano|mês|dia|hora|minuto|segundo|milissegundo"'

I hope this helps anyone facing this "issue".

Bolme answered 10/5, 2022 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.