1

我一直在关注本教程:
http : //dmnfarrell.github.io/bioinformatics/bokeh-maps(参见底部的所有代码),它创建了一个带有等值线的散景仪表板。滑块允许您更改正在显示的数据的年份。这样的仪表板可以导出为独立的 HTML 吗?如果是这样,怎么做?
如果我只创建地图的一个实例(一年),我可以显示()它并保存它,如下所示:

gdf = gdf[gdf['Year'] == 2018]
m = bokeh_plot_map(gdf, column=None, title='')
show(m)

但如果我跑

app = map_dash()
show(app)

我得到错误:

ValueError: "Invalid object to show. The object to passed to show must be one of:

* a LayoutDOM (e.g. a Plot or Widget or Layout)
* a Bokeh Application
* a callable suitable to an application FunctionHandler

尽管事实上如果我跑

app = map_dash()
pn.extension()
app

在 Jupyter Notebook 中,它按预期显示仪表板。

完整代码:

import pandas as pd
import geopandas as gpd
import json
import matplotlib as mpl
import pylab as plt

from bokeh.io import output_file, show, output_notebook, export_png
from bokeh.models import ColumnDataSource, GeoJSONDataSource, LinearColorMapper, ColorBar
from bokeh.plotting import figure
from bokeh.palettes import brewer

import panel as pn
import panel.widgets as pnw

shapefile = 'data/ne_110m_admin_0_countries.shp'
#Read shapefile using Geopandas
gdf = gpd.read_file(shapefile)[['ADMIN', 'ADM0_A3', 'geometry']]
#Rename columns.
gdf.columns = ['country', 'country_code', 'geometry']
gdf = gdf.drop(gdf.index[159])

owid = pd.read_csv('data/owid.csv').set_index('name')
def get_dataset(name,key=None,year=None):

    url = owid.loc[name].url
    df = pd.read_csv(url)
    if year is not None:
        df = df[df['Year'] == year]
    #Merge dataframes gdf and df_2016.
    if key is None:
        #name of column for plotting is always the third one
        key = df.columns[2]
    #merge with the geopandas dataframe
    merged = gdf.merge(df, left_on = 'country', right_on = 'Entity', how = 'left')
    merged[key] = merged[key].fillna(0)    
    return merged, key

def get_geodatasource(gdf):    
    """Get getjsondatasource from geopandas object"""
    json_data = json.dumps(json.loads(gdf.to_json()))
    return GeoJSONDataSource(geojson = json_data)

def bokeh_plot_map(gdf, column=None, title=''):
    """Plot bokeh map from GeoJSONDataSource """

    geosource = get_geodatasource(gdf)
    palette = brewer['OrRd'][8]
    palette = palette[::-1]
    vals = gdf[column]
    #Instantiate LinearColorMapper that linearly maps numbers in a range, into a sequence of colors.
    color_mapper = LinearColorMapper(palette = palette, low = vals.min(), high = vals.max())
    color_bar = ColorBar(color_mapper=color_mapper, label_standoff=8, width=500, height=20,
                         location=(0,0), orientation='horizontal')

    tools = 'wheel_zoom,pan,reset'
    p = figure(title = title, plot_height=400 , plot_width=850, toolbar_location='right', tools=tools)
    p.xgrid.grid_line_color = None
    p.ygrid.grid_line_color = None
    #Add patch renderer to figure
    p.patches('xs','ys', source=geosource, fill_alpha=1, line_width=0.5, line_color='black',  
              fill_color={'field' :column , 'transform': color_mapper})
    #Specify figure layout.
    p.add_layout(color_bar, 'below')
    return p

def map_dash():
    """Map dashboard"""

    from bokeh.models.widgets import DataTable
    map_pane = pn.pane.Bokeh(width=400)
    data_select = pnw.Select(name='dataset',options=list(owid.index))
    year_slider = pnw.IntSlider(start=1950,end=2018,value=2010)
    def update_map(event):
        gdf,key = get_dataset(name=data_select.value,year=year_slider.value)        
        map_pane.object = bokeh_plot_map(gdf, key)        
        return
    year_slider.param.watch(update_map,'value')
    year_slider.param.trigger('value')
    data_select.param.watch(update_map,'value')
    app = pn.Column(pn.Row(data_select,year_slider),map_pane)
    return app

app = map_dash()
4

0 回答 0