@grzegorz.malinowski
I haven’t studied the machinery of the aspect-ratio code, but my interpretation from the documentation is that it is more designed for the use case where a figure is analogous to a single graphical element, e.g. 2-D plot axes only, and doesn’t consider what happens when additional auxiliary objects like color bars or when really verbose labels for major ticks are used.
I personally have encountered scenarios where the problem has required precise aspect ratios to convey certain physical characteristics of the data being presented, and have either resorted to coming up with a scheme to compensate for the real estate lost to that other information or other workarounds (see following basic example to illustrate). The only other option I know of is to look at Holoviews that abstract alot of the low-level controls of Bokeh away from the user but provide controls for such things as square aspect ratios without you having to figure it out as a user.
Here’s one option that you might consider. The idea is to create a phantom (hidden) second plot that holds the colorbar so that it doesn’t take up space from the plot area you are actually interested in. It uses the extrema of the data only to minimize the amount of additional data that needs to be plotted while maintaining the colorbar scale of interest. The colorbar is added to the lefthand side of the phantom/hidden plot to make it appear attached to the visible plot.
The most obvious downside of this approach is that it constrains what you can do if you need toolbars. The other issue might be bookkeeping if you are dynamically. and interactively updating the plots.
The main benefit is obviously the avoiding the need for manually adjusting plot width to recover real estate lost to the colorbar.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
"""
import numpy as np
from bokeh.plotting import figure, show
from bokeh.layouts import row
from bokeh.models import LinearColorMapper, BasicTicker, ColorBar
data = np.random.rand(10,10)
color_mapper = LinearColorMapper(palette="Viridis256", low=0.0, high=1.0)
p = figure(width=350, height=350, x_range=(0.0,1.0), y_range=(0.0,1.0),
toolbar_location=None)
p.image(image=[data], color_mapper=color_mapper,
dh=[1.0], dw=[1.0], x=[0], y=[0])
# hidden plot with (min,max) data to support colobar
data_minmax = np.array([[data.min()],[data.max()]])
ph = figure(width=350, height=350, x_range=(0.0,1.0), y_range=(0.0,1.0),
toolbar_location=None)
imh = ph.image(image=[data_minmax], color_mapper=color_mapper,
dh=[1.0], dw=[1.0], x=[0], y=[0])
cb = ColorBar(color_mapper=color_mapper, ticker= BasicTicker(),
location=(0,0))
ph.add_layout(cb, 'left')
# Hide
ph.xaxis.visible = False
ph.xgrid.visible = False
ph.yaxis.visible = False
ph.ygrid.visible = False
ph.outline_line_color = None
imh.visible = False
show(row([p,ph]))