Bokeh Map not displaying - JavaScript Error

There is an interactive Bokeh that presently works in the classic notebook interface in launches from your instance after running %pip install sklearn first: here.
I note it uses interactive() (see below) and so trying to see if it is adaptable to fix your stuff.

I suspect your issue is related to the issue I think am seeing with ipywidget’s interact() and current MyBinder launches. However, Bokeh is much different & just switching to interactive as a work-around wasn’t enough, like it was in those other cases. Although, oddly that change was enough to get your size-adjusting and title widgets to display, but the plot wouldn’t.

So seeing that one here work that seems to use modern ipywidgets practices as evidenced by the use of output_figure = widgets.Output(), I wonder if it could be adapted. (You may wish to see here & note ipywidgets now need an output widget capturing the output to display.)

Below results in close to what you had and works at some level. I place this code in place of your plotting cell.
HUGE, STRANGE CAVEAT: It is super glitchy though. To get it to work first I have to try running it in JupyterLab and see the error that will be like Javascript Error: Error rendering Bokeh model: could not find #9ee3112f-b0fa-478a-86f5-f925a328c52b HTML tag, then stop the kernel, and run it in the classic interface, ignoring the error May also see NameError: name ‘mapper’ is not defined` that pops up the first time or two. Then it will sort of work by finally showing a plot. Usually shows the plot twice when cell first runs, but when you change the size or text it only loads one plot at that point.
Widgets work, but for some reason they show their values as text near them during the preparing stage. I don’t know why:

hide_code()
run_code()
from ipywidgets import interactive
from IPython.display import display, clear_output

"""Define callback function for the UI"""
def change_size(x):
    """This function is executed when a dropdown value is changed.
    It creates a new figure according to the new dropdown values."""
    p = heatmap(x,title.value)
    fig[0] = p
     
    with output_figure:
        clear_output(True)
        show(fig[0])
    fig[0]=p
     
    return x
 
def change_title(x):
    """This function is executed when a dropdown value is changed.
    It creates a new figure according to the new dropdown values."""
    p = heatmap(size.value,x)
    fig[0] = p
     
    with output_figure:
        clear_output(True)
        show(fig[0])
    fig[0]=p
     
    return x

def create_figure(x_var, y_var, data):
    """This is a helper function that creates a new figure and 
    plots values from all three species. x_var and y_var control
    the features on each axis."""
    species_colors=['coral', 'deepskyblue', 'darkblue']
    p = figure(title="",
               x_axis_label=x_var,
               y_axis_label=y_var)
    species_nr = 0
    for species in iris['target_names']:
        curr_dtps = data['target'] == species_nr
        circle = p.circle(
            data[x_var][curr_dtps],
            data[y_var][curr_dtps],
            line_width=2,
            color=species_colors[species_nr],
            name=species
            )
        species_nr += 1
    return p

def heatmap(size, title):

        p2 = figure(plot_width=size, plot_height=size, title=title,
                    x_range=(bbox2[0][0], bbox2[1][0]),y_range=(bbox2[0][1], bbox2[1][1]),
                    x_axis_type="mercator", y_axis_type="mercator")
        p2.title.text_font_size = '20pt'
        map_base = p2.add_tile(tile_provider2)
        map_base.level ='underlay'
        #convert source to selected dictionary value
        source = ColumnDataSource(viz_table)

        p2.rect(x='web_lon', y='web_lat', width=3500, height=3500, source=source,
                line_color=None, fill_color= transform("Population", mapper), alpha=0.07)

        p2.add_layout(color_bar, 'right')

        #show(p2)
        return p2
    
# The output widget is where we direct our figures
output_figure = widgets.Output()

if pop_file.value == "Select File":
    print("Waiting for Input")
else: 
    print("Preparing Plot...")
    data_store =pd.HDFStore(".\data\density.h5")
    
    viz_table = data_store["visuals"]                            
    
    lat_min = viz_table["latitude"].min()
    lat_max = viz_table["latitude"].max()
    lon_min = viz_table["longitude"].min()
    lon_max = viz_table["longitude"].max()
    
    
    #Have to convert to 2 decimal places otherwise to dense
    #round longitude
    viz_table["longitude"] = viz_table["longitude"].round(2)

    #round latitude
    viz_table["latitude"] = viz_table["latitude"].round(2)
    
       
    viz_table = viz_table.groupby(['longitude','latitude']).sum().reset_index()
    
    #Clear redundant lats/longs
    viz_table =viz_table.drop_duplicates(subset=["longitude", "latitude"], ignore_index=True)  
      
    viz_table['web_lon'], viz_table["web_lat"]  = transformer.transform(viz_table["latitude"].values, 
                                                                                      viz_table["longitude"].values)
    #grouped_poptable2 = grouped_poptable2[grouped_poptable2["Population"]!=0]
    new_total2 = round(sum(viz_table["Population"]))
        
    data_store["visuals"] = viz_table
    
    min_max_pts = [(lat_min, lon_min), (lat_max, lon_max)]
    bbox2 = []
    for pt in transformer.itransform(min_max_pts): 
        bbox2.append(pt)   

    size = widgets.IntText(
        value=600,
        description='Plot Size',
        disabled=False
    )

    title = widgets.Text(
        value='Population Density',
        description='Title',
        disabled=False
    )
    size_widget = widgets.interact(change_size,x=size);
    #size_widget.children[0].description = 'Plot Size'
    #size_widget.children[0].value = 600
    title_widget = widgets.interact(change_title,x=title);


    colors = list(RdYlGn[8]) 
    colors.reverse()
    #Is there a better color mapper?
    mapper = LinearColorMapper(palette=colors, low=viz_table.Population.min(),
                               high=viz_table.Population.max())

    color_bar = ColorBar(color_mapper=mapper, location=(0, 0),
                     ticker=BasicTicker(desired_num_ticks=len(colors)))

    
    # Create the default figure
    fig = []  # Storing the figure in a singular list is a bit of a 
              # hack. We need it to properly mutate the current
              # figure in our callbacks.
    p = heatmap(600,'Population Density')
    fig.append(p)
    with output_figure:
        show(fig[0])

    




    #heatmap_out = interactive(heatmap, size = size, title=title)
    #heatmap_out = widgets.interactive_output(heatmap, size = size, title=title)
    #heatmap_out = widgets.interactive_output(heatmap,{size: 'size', title:'title'})
    data_store.close()
    
    # This creates the menu 
    menu=widgets.VBox([size,
                       title])


    """Create the full app with menu and output"""
    # The Layout adds some styling to our app.
    # You can add Layout to any widget.
    app_layout = widgets.Layout(display='flex',
                    flex_flow='row nowrap',
                    align_items='center',
                    border='none',
                    width='100%',
                    margin='5px 5px 5px 5px')

    # The final app is just a box
    app=widgets.Box([output_figure], layout=app_layout)

    # Display the app
    display(app)

And with that being so weird to get working, I wonder if you original code works if you go through all that.


Related to it working if you go run the code in JupyterLab and then back to the classic interface, I wonder if what @psuchemedia (Tony Hirst) notes in his blog post has anything to do with it:

“One of the blockers I’ve had to date running … in JupyterLab was the requirement to have just a single instance of the widget running in a notebook. This is an artefact (I think) of the jp_proxy_widget having a hardwired HTML element reference that needs to be unique.”

1 Like