☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Responsive layout with reflow for screen rotations?

Community Support
ghomem
ghomem

Hi,

I currently have a layout like this:


grid = gridplot([
                  [ plot1, plot3, plot5, plot7 ],
                  [ plot2, plot4, plot6, plot8 ] ],
                  plot_width=PLOT_WIDTH, plot_height=PLOT_HEIGHT, toolbar_location=None, sizing_mode='scale_width')

which works fine on resolutions where width is greater than height (horizontal)

For vertical resolutions I would like this layout to be:

grid = gridplot([
                  [ plot1, plot3, ],
                  [ plot5, plot7  ],
                  [ plot2, plot4, ], 
                  [ plot6, plot8 ] ],
                  plot_width=PLOT_WIDTH, plot_height=PLOT_HEIGHT, toolbar_location=None, sizing_mode='scale_width')

Is it possible to have the layout conditional to the screen orientation?

Note that in this case scaling is not enough, as scaling horizontal content on a vertical device makes it unreadable. Ideally I would like to lay things out vertically if the resolution is vertical or becomes vertical due to a rotation.

⌁   Link to post
Bryan
Bryan

Bokeh’s simple built-in layouts are not sophisticated enough to do this, you would need to use one of the embedding APIs so embed Bokeh components individually into a responsive template.

⌁   Link to post
ghomem
ghomem

Hi @Bryan ,

Thanks for the answer.

I understand what you are saying in regards to the current situation. Would it be acceptable if I opened a feature request for this?

Allow me a moment to make the case.

I am using a good looking HTML/CSS template that essentially has a place holder for Bokeh layouts in the middle. With this, I am combining the tremendous technical power of Bokeh plots with the perks of a pretty looking template that works almost without HTML/CSS adjustments. This

<div class="content2">{{ embed(roots.section1) }}</div>
<div style="display: flex; justify-content: flex-end">{{ embed(roots.section1_controls) }}</div>

is enough to make things work, without having to fiddle with unfamiliar and potentially complicated HTML. Example: https://coviz.io/

Chopping the Bokeh layouts into individual plots which are fed into a responsive HTML grid increases the difficulty by an order of magnitude for non HTML specialists. It also breaks a bit the concern separation between the HTML and python part, which I imagine that sometime happens (a team works on the template around the charts, another team works in the technical Bokeh part).

I would speculate that supporting conditional layouts would help many users, especially since mobile is growing.

Of course, if this is technically not possible I shall not bother you more :slight_smile:

Thanks for the support. And thanks for Bokeh.

Cheers
Gustavo

⌁   Link to post
Bryan
Bryan

Speaking plainly and directly, probably not.

The history of managed DOM layout and Bokeh has more or less been one of repeated attempts to re-invent a very expensive wheel, but always coming up short in various ways. Browsers and the common front-end libraries have had person-decades (if not person-centuries) of effort poured into them. We will never be able to match their levels of development, testing, or platform coverage. Meanwhile, there has been a near constant stream of calls for “I just want to put Bokeh things in React” (or Angular, or Vue, take your pick) that have not been adequately addressed while we tried to boil the ocean ourselves.

Rather that trying to more, our plan for 3.x is specifically the opposite: to get out of the layout business as much as possible, and focus on the things we can be best at. We will always have to manage the canvas layout, and we will continue to offer simple, “dumb” row, column, grid, etc. for simple cases. But trying to manage sophisticated DOM layout ourselves has not been a valuable use of very limited resources. There are existing, popular, highly-developed tools for designing responsive pages, and the best thing we can do is to get out of the way of users trying to take advantage of them.

⌁   Link to post
ghomem
ghomem

Hi @Bryan ,

I appreciate the honest reply and I understand what you mean. Is it also out of question to expose the browser window size to the Bokeh code, so that we can do

if width > = length:
    grid = make_horizontal_layout()
else:
    grid = make_vertical_layout()

?

This would be clean enough on the python side of things :slight_smile:

Thank you.

⌁   Link to post
Bryan
Bryan

My offhand speculation (based purely on past experiences, not any concrete investigation) is that that might prove difficult to make completely reliable. But it seems worth looking at cc @mateusz or thoughts. You might also consider opening a GitHub development discussion which is a good place to propose features that might require more up-front discussion or consideration.

⌁   Link to post
ghomem
ghomem

I currently can “pull” the dimensions from the Javascript document like this:

# this callback runs on the browser and updates the server side data source from the dimensions data got via Javascript
mycallback = CustomJS( args=dict(ds=window_size_data_source), code="""
var width, height;
var new_data = {};
height = window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
width  = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
console.log("Javascript callback", height, width);

// for some reason the right side needs to be a list, otherwise we have a server side error
new_data['height'] = [height];
new_data['width' ] = [width];
ds.data = new_data;
ds.change.emit();

""")

# this callbacks takes action on the server side upon dimensions change
def on_source_change(attr, old, new):

    width  = new['width'][0]
    height = new['height'][0]

    print('current dimensions', width, height)

    if width >= height:
        print('orientation is horizontal')
        # switch layout to verticals python side

    else:
        print('orientation is vertical')
        # switch layout to horizontal python side


# this connects a data change on the data source to the server side callback
window_size_data_source.on_change('data', on_source_change)

# TODO: how to have this on a window resize event and during the page load
date_slider_map.js_on_change('value_throttled', mycallback)

The problem (see the last code line) is that this is being triggered by a widget and I’d need this on page load and /or window resize event.

⌁   Link to post
Bryan
Bryan

Right, this would entail new development for sure, which is my suggestion for opening a GH discussion. cc also @Philipp_Rudiger who I believe is also interested in more document-level events.

Edit: I guess for completeness I will mention the terrible option, which is that a Python callback for document init is currently available. Presumably that callback could set some random property value just in order to then trigger a CustomJS callback in the client. I don’t think this is an especially good idea.

⌁   Link to post
Bryan
Bryan

You are the second person to report this, I’m really at a loss as to what might be going on. There are no settings I can find related to GH disucssions permissions and GH docs explicity state that “anyone with access to the repository” should be able to post. I guess I will have to open a support ticket with GH about it.

⌁   Link to post
ghomem
ghomem

I am not sure flexbox does what I am after. I want to keep the current grid layout, with scaling, unless the browser window becomes “vertical”. Or, better said, until a minimum width, for which scaling makes the plots too small, is hit. Like here:

This sounds like a hybrid between flexbox and gridbox, because it is a grid that flexes only after a certain width threshold is hit.

The grid on the app above has a certain layout that follows a certain logic and it makes sense to retain the grid as it is (scaled) until a certain width threshold is hit, below which we accept graceful degradation, i.e., we sacrifice the grid layout for readability because scaling would not longer help.

⌁   Link to post
ghomem
ghomem

Hi @Bryan ,

As there is no progress on the github discussion yet and I understand such things take time to implement properly, could you please share how to use a python callback for document init?

I would at least run an experiment with this.

Thanks in advance.

⌁   Link to post
ghomem
ghomem

Thanks @Bryan.

Then how would that call back allow me to pull the window size from the Javascript world? It would maybe toggle state on a hidden Toggle that was connected to a CustomJS callback, that would in turn invoke the call back that sets the layout?

⌁   Link to post
Bryan
Bryan

There’s not any especially clean way I can think of. Did someone suggest otherwise? Maybe something like:

  • Python DocumentReady sets some property value just to trigger a CustomJS
  • JavaScript CustomJS reads window size and sets as a property value on some other object
  • Python property change callback uses window size
⌁   Link to post
ghomem
ghomem

Hello,

So here is the progress on this matter:

Click here using your phone:

https://coviz.io/

and compare to the result on a desktop.

This is not perfect but is much better than before. There are absolutely no performance problems on reflowing the layouts like I am doing here:

If we had a window resize event that could do some work after the user finishes resizing the window the situation would be much improved. Any ideas about that?

Thanks for great support.

⌁   Link to post
ghomem
ghomem

Thanks. Here is the issue:

⌁   Link to post
ghomem
ghomem

Hi @Bryan ,

Just wanted to leave you a note about the window size versus reflow topic: the method you provided above is proven to work. It enabled much progress on making the Bokeh app more mobile friendly whereas keeping the python code clean and tidy, and not mixed with the HTML.

We are experimenting with a PWA:

https://coviz.io/pwa/

You will see that there is a funky loading behavior that is caused by the necessity of using the DocumentReady callback hack, instead of having the window size from the beginning. Having the window size at the python side and having access to a window resize event would clean up the situation.

That said, what we are doing now is much better than nothing :slight_smile: It makes a big difference for mobile browsing.

Thanks for the support :slight_smile:

⌁   Link to post

End of archived discussion · Replies are disabled