There’s a few things going on. First, a range has nothing to do with pixels. A range is simply a stated numerical span to cover the entire distance of the axis, whatever that is. In this case you have set a plot canvas width of 600px, so you are asking for a range from 0 to 300 over a distance of of 600 pixels, so that’s clearly not a 1-1 match. If you wanted the axis to “match up” with pixels of the image, you’d need to specify a range of, say, (0, 600)
, and then the image would occupy a quarter of the stated range.
Except that won’t be right either, because the plot canvas dimensions are inclusive of the space occupied by the axes and their labels, etc. so those would need to be subtracted out. In that case that’s probably about ~40px so you’d rally need to specify a range to cover just the size of that subregion spanned by the exes frame, say (0, 560)
.
Unfortunately, the exact information is not actually available from Python. Being a tool for interactive datavis in browsers, all the actual work, including computing the space needed to occupy the axes, is computed in JavaScript, in the browser, only after all the Python code has finished and exited.
I won’t say this task is impossible in Bokeh. There are things you can do like setting the axes min_border
properties to ensure they never occupy less than that space and then also make sure your axis tick labels are formatted or oriented to never need more than that space. Then you could (fairly) reliably compute the pixel size of the interior frame regions yourself. But it’s pretty finicky and there’s still probably other things that have to be dealt (e.g. titles and toolbars). I think there are some relevant topics on Stack Overflow over the years.
TLDR; This is not a great use-case for Bokeh. Bokeh is primarily geared for interactivity like panning and zooming, i.e., all the cases where the image does not stay pixel matched. If it is a hard requirement, there may be other tools to consider that would be better suited.
It does occur to me that it would probably not be too hard to add a readonly AxisScreenRange
that simply reports the start and end of the internal axis frames, whatever they are at any moment. They would not be settable, since setting would be tantamount to adjusting the layout, and layout is handled separately. If that sounds useful, please feel free to open a GitHub Issue to propose it for new development.