It seems to me that @marckassay code still has the same problem as we already had, i.e. need of a refresh.
I looked at this with the browser inspection tools and the problem is that the loading of the font of the bokeh plot starts at the beginning of the rendering of the bokeh plot and is not available in due time.
So I checked on preloading techniques as suggested by @Marc.
Here is the resulting code with no need of refresh and no FOUC.
import panel as pn
import holoviews as hv
from bokeh.themes import Theme as _BkTheme
pn.extension()
font_url = "https://fonts.gstatic.com/s/architectsdaughter/v11/KtkxAKiDZI_td1Lkx62xHZHDtgO_Y-bvTYlg4w.woff2"
font_local_name = "scriptlook"
font_preload = f'<link rel="preload" as="font" href="{font_url}" crossorigin="anonymous">'
css = f'''<style>
@font-face {{
font-family: {font_local_name};
src: url({font_url}) format("woff2");}}
</style>
'''
template = f'''
{{% extends base %}}
{{% block preamble %}}
{font_preload}
{css}
{{% endblock %}}
'''
tmpl = pn.Template(template)
font_theme = {
'attrs' : {
'Axis': {
'major_label_text_color': 'green',
'major_label_text_font' : font_local_name,
'major_label_text_font_size': '18pt',
'axis_label_text_color': 'red',
'axis_label_text_font': font_local_name
},
'Title': {
'text_font': font_local_name,
'text_color': 'blue',
'text_alpha' : 1.0
}
}
}
theme = _BkTheme(json=font_theme)
hvr = hv.renderer('bokeh')
hvr.theme = theme
h = hv.Scatter([(0,0),(1,1)])
h = h.opts(title='Scatter',fontsize=30,width=800,height=400,toolbar=None)
tmpl.add_panel('A', pn.pane.HTML("<h1>Custom font</h1>"))
tmpl.add_panel('B', pn.pane.HoloViews(h))
tmpl.show(title='custom font example')
This is done through a custom template.
For a cleaner code, you can put bokeh style, css and the font in an asset directory and use the asset declaration mechanism of panel.
import panel as pn
import holoviews as hv
from bokeh.themes import Theme as _BkTheme
pn.extension()
template = '''
{% extends base %}
{% block preamble %}
<link rel="preload" as="font" href="assets/ArchitectsDaughter-Regular.ttf" crossorigin="anonymous">
<link rel="preload" as="style" href="assets/font.css" >
<link rel="stylesheet" href="assets/font.css" >
{% endblock %}
'''
tmpl = pn.Template(template)
theme = _BkTheme(filename = 'assets/font_theme.yaml')
hvr = hv.renderer('bokeh')
hvr.theme = theme
h = hv.Scatter([(0,0),(1,1)])
h = h.opts(title='Scatter',fontsize=30,width=800,height=400,toolbar=None)
tmpl.add_panel('A', pn.pane.HTML("<h1>Custom font</h1>"))
tmpl.add_panel('B', pn.pane.HoloViews(h))
tmpl.show(title='custom font example',static_dirs={'assets': './assets'})
where font.css
is
@font-face {
font-family: "scriptlook";
src: url("/assets/ArchitectsDaughter-Regular.ttf")
}
and font_theme.yaml
is
attrs :
Axis:
major_label_text_color: 'green'
major_label_text_font: scriptlook
major_label_text_font_size: '18pt'
axis_label_text_color: 'red'
axis_label_text_font: scriptlook
Title:
text_font: scriptlook
text_color: 'blue'
text_alpha : 1.0
Notice that to make this works, you have to preload the font and the css file, AND you also have to declare that you use this preloaded css file, i.e. you need all this :
{% block preamble %}
<link rel="preload" as="font" href="assets/ArchitectsDaughter-Regular.ttf" crossorigin="anonymous">
<link rel="preload" as="style" href="assets/font.css">
<link rel="stylesheet" href="assets/font.css">
{% endblock %}