Royalblue
Royalblue

Reputation: 691

How to fit bokeh plot size dynamically

My questions is very similar to the one asked yesterday: Bokeh resize plot dynamically

But since I feel a solution may be a little bit different between the two, I would like to post my own. also I copy the entire code so that anyone can just copy/paste and run it.

In the below code, I basically want the second Bokeh plot to take up the entire view port when I click on the title and return to the original size on the next click.

As a side information, I borrowed part of the code from github. Bootstrap4 is used for css. TweenMax for animation and of course the plotting library is Bokeh. The containing bootstrap card size changes as expected but the plot does not. if I resize the browser, somehow the plot resizes itself.

import pandas as pd
import numpy as np
import io
import random
from jinja2 import Template
from bokeh.embed import components
from bokeh.plotting import figure
from bokeh.resources import INLINE
from bokeh.util.browser import view


PLOT_OPTIONS = dict(plot_width=800, plot_height=300)
SCATTER_OPTIONS = dict(size=12, alpha=0.5)

data = lambda: [random.choice([i for i in range(100)]) for r in range(10)]

# red = figure(sizing_mode='scale_width', tools='pan', **PLOT_OPTIONS)
red = figure(sizing_mode='stretch_both', tools='pan')
red.scatter(data(), data(), color="red", **SCATTER_OPTIONS)

# blue = figure(sizing_mode='fixed', tools='pan', **PLOT_OPTIONS)
blue = figure(sizing_mode='stretch_both', tools='pan', id="blue_fig")
blue.scatter(data(), data(), color="blue", **SCATTER_OPTIONS)

green = figure(sizing_mode='scale_width', tools='pan', **PLOT_OPTIONS)
green.scatter(data(), data(), color="green", **SCATTER_OPTIONS)


########## RENDER PLOTS ################

# Define our html template for out plots
template = Template('''<!DOCTYPE html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.4/TweenMax.min.js"></script>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
{{ js_resources }}
{{ css_resources }}
</head>
<body>
<div id="panel">
<div class="col-md-6" id="card1">
    <div class="card">
        <div class="card-body">
            <div class="row">
                <div class="col-sm-4">
                    <h4 class="card-title mb-0">plot 1</h4>
                </div>
            </div>
            <div id="div1" style="height:400px;">
            {{ div1 }}
            </div>
        </div>
    </div>
</div>
<div class="col-md-6" id="card2">
    <div class="card">            
        <div class="card-body" style="background:yellow; border:solid 1px red">
            <div class="row">
                <div class="col-sm-4">
                    <h4 class="card-title mb-0"><a href='#' id="plot2">plot 2</a></h4>
                </div>
            </div>        
            <div id="div2" style="height:400px;">
            {{ div2 }}
            </div>
        </div>
    </div>
</div>
</div>
<script>
(function($){
   var i = 0;
   var po = $('#panel').offset();
   var co = $('#card2').offset();   
   var x=0, y=po.top-co.top;
    $('#plot2').click(function(){
      if(i==0){    
        TweenMax.to($("#card2"), 0.5, {x:x, y:y, className:"col-md-12"});
        TweenMax.to($("#div2"), 0.5, {height:800});
        i = 1;
      } else {
        TweenMax.to($("#card2"), 0.5, {x:0, y:0, className:"col-md-6"});
        TweenMax.to($("#div2"), 0.5, {height:400});   
        i = 0;   
      }
      $(window).resize();
      $(window).trigger('resize');
    });      
})(jQuery);
</script>
</body>
</html>
''')

resources = INLINE

js_resources = resources.render_js()
css_resources = resources.render_css()

script, div = components(red)
div1 = div+script

script, div = components(blue)
div2 = div+script

html = template.render(js_resources=js_resources,
                       css_resources=css_resources,
                       div1=div1,
                       div2=div2)

filename = 'embed_multiple_responsive.html'

with io.open(filename, mode='w', encoding='utf-8') as f:
    f.write(html)

view(filename)

Upvotes: 0

Views: 5795

Answers (1)

HYRY
HYRY

Reputation: 97281

Here is the modification to your code:

add an id argument to figure():

blue = figure(sizing_mode='stretch_both', tools='pan', id="blue_fig")

add onUpdate event and call Bokeh.index["blue_fig"].resize():

TweenMax.to($("#div2"), 0.5, {height:800, onUpdate:function(){Bokeh.index["blue_fig"].resize();}});
TweenMax.to($("#div2"), 0.5, {height:400, onUpdate:function(){Bokeh.index["blue_fig"].resize();}});

if the figure is complex and resize() is slow, change onUpdate to onComplete.

Upvotes: 1

Related Questions