def test_js_on_change_executes(self, bokeh_model_page): button = Dropdown(label="Dropdown button", menu=items, css_classes=["foo"]) button.js_on_change('value', CustomJS(code=RECORD("value", "cb_obj.value"))) page = bokeh_model_page(button) button = page.driver.find_element_by_class_name('foo') button.click() item = page.driver.find_element_by_link_text("Item 1") item.click() results = page.results assert results == {'value': "item_1_value"} button = page.driver.find_element_by_class_name('foo') button.click() item = page.driver.find_element_by_link_text("Item 3") item.click() results = page.results assert results == {'value': "item_3_value"} button = page.driver.find_element_by_class_name('foo') button.click() item = page.driver.find_element_by_link_text("Item 2") item.click() results = page.results assert results == {'value': "item_2_value"} assert page.has_no_console_errors()
def scatterSelect(): colormap = {'0': 'red', '1': 'green', 'virginica': 'blue'} a=[1,2,3,4,5,6,7,8,9] b=[2,3,4,5,6,7,8,9,10] c=[2,5,6,8,9,7,2,2,4] d=['red','green','green','blue','red','green','green','blue','green'] source=ColumnDataSource(data={'a':a,'b':b,'c':c,'d':d,'x':a,'y':b,'color':d}) p=figure(title = "x-y", sizing_mode="fixed", plot_width=600, plot_height=400,tools='pan,wheel_zoom,box_zoom,save,reset') p.toolbar.logo=None p.add_tools( HoverTool( show_arrow=True, line_policy='next', tooltips=[ ('X_value', '$data_x'), ('Y_value', '$data_y') ] ) ) p.scatter(x='x',y='y', color='color',source=source) from bokeh.layouts import column,row from bokeh.models import Dropdown callback1 = CustomJS(args=dict(source=source,axis=p.xaxis[0]), code=""" var data = source.data; var f = cb_obj.value data['x']=data[f] axis.axis_label=f source.change.emit(); """) callback2 = CustomJS(args=dict(source=source,axis=p.yaxis[0]), code=""" var data = source.data; var f = cb_obj.value data['y']=data[f] axis.axis_label=f source.change.emit(); """) dp1 = Dropdown(label="X value",menu=[('aa','a'),('bb','b'),('cc','c')],default_value='b') dp1.js_on_change('value', callback1) dp2 = Dropdown(label="Y value",menu=['a','b','c'],default_value='b') dp2.js_on_change('value', callback2) layout = column(row(dp1,dp2), p) return json.dumps(json_item(layout))
def geoplot(gdf_in, fig=None, figsize=None, title="", xlabel="Longitude", ylabel="Latitude", color="blue", colormap=None, colormap_uselog=False, colormap_range=None, category=None, dropdown=None, slider=None, slider_range=None, slider_name="", show_colorbar=True, xrange=None, yrange=None, hovertool=True, hovertool_columns=[], simplify_shapes=None, tile_provider="CARTODBPOSITRON_RETINA", tile_provider_url=None, toolbar_location=None, show_figure=True, return_figure=True, return_html=False, legend=True, **kwargs): """Doc-String: TODO""" gdf = gdf_in.copy() #Check layertypes: layertypes = [] if "Point" in str(gdf.geom_type.unique()): layertypes.append("Point") if "Line" in str(gdf.geom_type.unique()): layertypes.append("Line") if "Polygon" in str(gdf.geom_type.unique()): layertypes.append("Polygon") if len(layertypes) > 1: raise Exception( "Can only plot GeoDataFrames/Series with single type of geometry (either Point, Line or Polygon). Provided is a GeoDataFrame/Series with types: %s" % layertypes) #Get and check provided parameters for geoplot: figure_options = { "title": title, "x_axis_label": xlabel, "y_axis_label": ylabel, "plot_width": 600, "plot_height": 400, "toolbar_location": toolbar_location, "active_scroll": "wheel_zoom" } if not isinstance(figsize, type(None)): width, height = figsize figure_options["plot_width"] = width figure_options["plot_height"] = height if not isinstance(fig, type(None)): raise NotImplementedError("Parameter <figure> not yet implemented.") #Convert GeoDataFrame to Web Mercador Projection: gdf.to_crs({'init': 'epsg:3857'}, inplace=True) #Simplify shapes if wanted: if isinstance(simplify_shapes, numbers.Number): if layertypes[0] in ["Line", "Polygon"]: gdf["geometry"] = gdf["geometry"].simplify(simplify_shapes) elif not isinstance(simplify_shapes, type(None)): raise ValueError( "<simplify_shapes> parameter only accepts numbers or None.") #Check for category, dropdown or slider (choropleth map column): category_options = 0 if not isinstance(category, type(None)): category_options += 1 category_columns = [category] if not isinstance(dropdown, type(None)): category_options += 1 category_columns = dropdown if not isinstance(slider, type(None)): category_options += 1 category_columns = slider if category_options > 1: raise ValueError( "Only one of <category>, <dropdown> or <slider> parameters is allowed to be used at once." ) #Check for category (single choropleth plot): if isinstance(category, type(None)): pass elif isinstance(category, (list, tuple)): raise ValueError( "For <category>, please provide an existing single column of the GeoDataFrame." ) elif category in gdf.columns: pass else: raise ValueError( "Could not find column '%s' in GeoDataFrame. For <category>, please provide an existing single column of the GeoDataFrame." % category) #Check for dropdown (multiple choropleth plots via dropdown selection): if isinstance(dropdown, type(None)): pass elif not isinstance(dropdown, (list, tuple)): raise ValueError( "For <dropdown>, please provide a list/tuple of existing columns of the GeoDataFrame." ) else: for col in dropdown: if col not in gdf.columns: raise ValueError( "Could not find column '%s' for <dropdown> in GeoDataFrame. " % col) #Check for slider (multiple choropleth plots via slider selection): if isinstance(slider, type(None)): pass elif not isinstance(slider, (list, tuple)): raise ValueError( "For <slider>, please provide a list/tuple of existing columns of the GeoDataFrame." ) else: for col in slider: if col not in gdf.columns: raise ValueError( "Could not find column '%s' for <slider> in GeoDataFrame. " % col) if not isinstance(slider_range, type(None)): if not isinstance(slider_range, Iterable): raise ValueError( "<slider_range> has to be a type that is iterable like list, tuple, range, ..." ) else: slider_range = list(slider_range) if len(slider_range) != len(slider): raise ValueError( "The number of elements in <slider_range> has to be the same as in <slider>." ) steps = [] for i in range(len(slider_range) - 1): steps.append(slider_range[i + 1] - slider_range[i]) if len(set(steps)) > 1: raise ValueError( "<slider_range> has to have equal step size between each elements (like a range-object)." ) else: slider_step = steps[0] slider_start = slider_range[0] slider_end = slider_range[-1] #Check colormap if either <category>, <dropdown> or <slider> is choosen: if category_options == 1: if isinstance(colormap, type(None)): colormap = blue_colormap elif isinstance(colormap, (tuple, list)): if len(colormap) > 1: pass else: raise ValueError( "<colormap> only accepts a list/tuple of at least two colors or the name of one of the following predefined colormaps (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (list(all_palettes.keys()))) elif isinstance(colormap, str): if colormap in all_palettes: colormap = all_palettes[colormap] colormap = colormap[max(colormap.keys())] else: raise ValueError( "Could not find <colormap> with name %s. The following predefined colormaps are supported (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (colormap, list(all_palettes.keys()))) else: raise ValueError( "<colormap> only accepts a list/tuple of at least two colors or the name of one of the following predefined colormaps (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (list(all_palettes.keys()))) else: if isinstance(color, str): colormap = [color] else: raise ValueError( "<color> has to be a string specifying the fill_color of the map glyph." ) #Create Figure to draw: if "Point" in layertypes or "Line" in layertypes: figure_options["output_backend"] = "webgl" p = figure(x_axis_type="mercator", y_axis_type="mercator", **figure_options) #Get ridd of zoom on axes: for t in p.tools: if type(t) == WheelZoomTool: t.zoom_on_axis = False #Add Tile Source as Background: p = _add_backgroundtile(p, tile_provider, tile_provider_url) # Hide legend if wanted: if not legend: p.legend.visible = False legend = "GeoLayer" #Define colormapper: if len(colormap) == 1: kwargs["fill_color"] = colormap[0] elif not isinstance(category, type(None)): #Check if category column is numerical: if not issubclass(gdf[category].dtype.type, np.number): raise NotImplementedError( "<category> plot only yet implemented for numerical columns. Column '%s' is not numerical." % category) field = category colormapper_options = {"palette": colormap} if not isinstance(colormap_range, type(None)): if not isinstance(colormap_range, (tuple, list)): raise ValueError( "<colormap_range> can only be 'None' or a tuple/list of form (min, max)." ) elif len(colormap_range) == 2: colormapper_options["low"] = colormap_range[0] colormapper_options["high"] = colormap_range[1] else: colormapper_options["low"] = gdf[field].min() colormapper_options["high"] = gdf[field].max() if colormap_uselog: colormapper = LogColorMapper(**colormapper_options) else: colormapper = LinearColorMapper(**colormapper_options) kwargs["fill_color"] = {'field': "Colormap", 'transform': colormapper} legend = str(field) elif not isinstance(dropdown, type(None)): #Check if all columns in dropdown selection are numerical: for col in dropdown: if not issubclass(gdf[col].dtype.type, np.number): raise NotImplementedError( "<dropdown> plot only yet implemented for numerical columns. Column '%s' is not numerical." % col) field = dropdown[0] colormapper_options = {"palette": colormap} if not isinstance(colormap_range, type(None)): if not isinstance(colormap_range, (tuple, list)): raise ValueError( "<colormap_range> can only be 'None' or a tuple/list of form (min, max)." ) elif len(colormap_range) == 2: colormapper_options["low"] = colormap_range[0] colormapper_options["high"] = colormap_range[1] else: colormapper_options["low"] = gdf[dropdown].min().min() colormapper_options["high"] = gdf[dropdown].max().max() if colormap_uselog: colormapper = LogColorMapper(**colormapper_options) else: colormapper = LinearColorMapper(**colormapper_options) kwargs["fill_color"] = {'field': "Colormap", 'transform': colormapper} legend = "Geolayer" ##str(field) elif not isinstance(slider, type(None)): #Check if all columns in dropdown selection are numerical: for col in slider: if not issubclass(gdf[col].dtype.type, np.number): raise NotImplementedError( "<slider> plot only yet implemented for numerical columns. Column '%s' is not numerical." % col) field = slider[0] colormapper_options = {"palette": colormap} if not isinstance(colormap_range, type(None)): if not isinstance(colormap_range, (tuple, list)): raise ValueError( "<colormap_range> can only be 'None' or a tuple/list of form (min, max)." ) elif len(colormap_range) == 2: colormapper_options["low"] = colormap_range[0] colormapper_options["high"] = colormap_range[1] else: colormapper_options["low"] = gdf[slider].min().min() colormapper_options["high"] = gdf[slider].max().max() if colormap_uselog: colormapper = LogColorMapper(**colormapper_options) else: colormapper = LinearColorMapper(**colormapper_options) kwargs["fill_color"] = {'field': "Colormap", 'transform': colormapper} legend = "Geolayer" ##str(field) #Check for Hovertool columns: if hovertool: if not isinstance(hovertool_columns, (list, tuple)): if hovertool_columns == "all": hovertool_columns = list( filter(lambda col: col != "geometry", df_shapes.columns)) else: raise ValueError( "<hovertool_columns> has to be a list of columns of the GeoDataFrame or the string 'all'." ) elif len(hovertool_columns) == 0: if not isinstance(category, type(None)): hovertool_columns = [category] elif not isinstance(dropdown, type(None)): hovertool_columns = dropdown elif not isinstance(slider, type(None)): hovertool_columns = slider else: hovertool_columns = [] else: for col in hovertool_columns: if col not in gdf.columns: raise ValueError( "Could not find columns '%s' in GeoDataFrame. <hovertool_columns> has to be a list of columns of the GeoDataFrame or the string 'all'." % col) else: if isinstance(category, type(None)): hovertool_columns = [] else: hovertool_columns = [category] #Reduce DataFrame to needed columns: if category_options == 0: gdf = gdf[hovertool_columns + ["geometry"]] else: gdf = gdf[list(set(hovertool_columns) | set(category_columns)) + ["geometry"]] gdf["Colormap"] = gdf[field] field = "Colormap" #Create GeoJSON DataSource for Plot: geo_source = GeoJSONDataSource(geojson=gdf.to_json()) #Draw Glyph on Figure: layout = None if "Point" in layertypes: if "line_color" not in kwargs: kwargs["line_color"] = kwargs["fill_color"] p.scatter(x="x", y="y", source=geo_source, legend=legend, **kwargs) if "Line" in layertypes: if "line_color" not in kwargs: kwargs["line_color"] = kwargs["fill_color"] p.multi_line(xs="xs", ys="ys", source=geo_source, legend=legend, **kwargs) if "Polygon" in layertypes: if "line_color" not in kwargs: kwargs["line_color"] = "black" #Plot polygons: p.patches(xs="xs", ys="ys", source=geo_source, legend=legend, **kwargs) if hovertool and (category_options == 1 or len(hovertool_columns) > 0): my_hover = HoverTool() my_hover.tooltips = [(str(col), "@{%s}" % col) for col in hovertool_columns] p.add_tools(my_hover) if show_colorbar and category_options == 1: colorbar_options = { "color_mapper": colormapper, "label_standoff": 12, "border_line_color": None, "location": (0, 0) } if colormap_uselog: colorbar_options["ticker"] = LogTicker() colorbar = ColorBar(**colorbar_options) p.add_layout(colorbar, "right") if not isinstance(dropdown, type(None)): #Define Dropdown widget: dropdown_widget = Dropdown(label="Select Choropleth Layer", menu=list(zip(dropdown, dropdown))) #Define Callback for Dropdown widget: callback = CustomJS(args=dict(dropdown_widget=dropdown_widget, geo_source=geo_source, p=p), code=""" //Change selection of field for Colormapper for choropleth plot: geo_source.data["Colormap"] = geo_source.data[dropdown_widget.value]; geo_source.change.emit(); //p.legend[0].items[0]["label"] = dropdown_widget.value; """) dropdown_widget.js_on_change("value", callback) #Add Dropdown widget above the plot: layout = column(dropdown_widget, p) if not isinstance(slider, type(None)): if slider_range is None: slider_start = 0 slider_end = len(slider) - 1 slider_step = 1 value2name = ColumnDataSource({ "Values": np.arange(slider_start, slider_end + slider_step, slider_step), "Names": slider }) #Define Slider widget: slider_widget = Slider(start=slider_start, end=slider_end, value=slider_start, step=slider_step, title=slider_name) #Define Callback for Slider widget: callback = CustomJS(args=dict( slider_widget=slider_widget, geo_source=geo_source, value2name=value2name, ), code=""" //Change selection of field for Colormapper for choropleth plot: var slider_value = slider_widget.value; for(i=0; i<value2name.data["Names"].length; i++) { if (value2name.data["Values"][i] == slider_value) { var name = value2name.data["Names"][i]; } } geo_source.data["Colormap"] = geo_source.data[name]; geo_source.change.emit(); """) slider_widget.js_on_change("value", callback) #Add Slider widget above the plot: layout = column(slider_widget, p) # Set click policy for legend: p.legend.click_policy = "hide" # Display plot and if wanted return plot: if isinstance(layout, type(None)): layout = p # Display plot if wanted if show_figure: show(layout) #Return as (embeddable) HTML if wanted: if return_html: return embedded_html(layout) #Return plot: if return_figure: return layout
def geoplot( gdf_in, figure=None, figsize=None, title="", xlabel="Longitude", ylabel="Latitude", xlim=None, ylim=None, color="blue", colormap=None, colormap_uselog=False, colormap_range=None, category=None, dropdown=None, slider=None, slider_range=None, slider_name="", show_colorbar=True, colorbar_tick_format=None, xrange=None, yrange=None, hovertool=True, hovertool_columns=[], hovertool_string=None, simplify_shapes=None, tile_provider="CARTODBPOSITRON_RETINA", tile_provider_url=None, tile_attribution="", tile_alpha=1, panning=True, zooming=True, toolbar_location="right", show_figure=True, return_figure=True, return_html=False, legend=True, webgl=True, **kwargs ): """Doc-String: TODO""" # Imports: import bokeh.plotting from bokeh.plotting import show from bokeh.models import ( HoverTool, LogColorMapper, LinearColorMapper, GeoJSONDataSource, WheelZoomTool, ColorBar, BasicTicker, LogTicker, Dropdown, Slider, ColumnDataSource, ) from bokeh.models.callbacks import CustomJS from bokeh.models.widgets import Dropdown from bokeh.palettes import all_palettes from bokeh.layouts import row, column # Make a copy of the input geodataframe: gdf = gdf_in.copy() # Check layertypes: if type(gdf) != pd.DataFrame: layertypes = [] if "Point" in str(gdf.geom_type.unique()): layertypes.append("Point") if "Line" in str(gdf.geom_type.unique()): layertypes.append("Line") if "Polygon" in str(gdf.geom_type.unique()): layertypes.append("Polygon") if len(layertypes) > 1: raise Exception( "Can only plot GeoDataFrames/Series with single type of geometry (either Point, Line or Polygon). Provided is a GeoDataFrame/Series with types: %s" % layertypes ) else: layertypes = ["Point"] # Get and check provided parameters for geoplot: figure_options = { "title": title, "x_axis_label": xlabel, "y_axis_label": ylabel, "plot_width": 600, "plot_height": 400, "toolbar_location": toolbar_location, "active_scroll": "wheel_zoom", "x_axis_type": "mercator", "y_axis_type": "mercator", } if not figsize is None: width, height = figsize figure_options["plot_width"] = width figure_options["plot_height"] = height if webgl: figure_options["output_backend"] = "webgl" if type(gdf) != pd.DataFrame: # Convert GeoDataFrame to Web Mercator Projection: gdf.to_crs({"init": "epsg:3857"}, inplace=True) # Simplify shapes if wanted: if isinstance(simplify_shapes, numbers.Number): if layertypes[0] in ["Line", "Polygon"]: gdf["geometry"] = gdf["geometry"].simplify(simplify_shapes) elif not simplify_shapes is None: raise ValueError( "<simplify_shapes> parameter only accepts numbers or None." ) # Check for category, dropdown or slider (choropleth map column): category_options = 0 if not category is None: category_options += 1 category_columns = [category] if not dropdown is None: category_options += 1 category_columns = dropdown if not slider is None: category_options += 1 category_columns = slider if category_options > 1: raise ValueError( "Only one of <category>, <dropdown> or <slider> parameters is allowed to be used at once." ) # Check for category (single choropleth plot): if category is None: pass elif isinstance(category, (list, tuple)): raise ValueError( "For <category>, please provide an existing single column of the GeoDataFrame." ) elif category in gdf.columns: pass else: raise ValueError( "Could not find column '%s' in GeoDataFrame. For <category>, please provide an existing single column of the GeoDataFrame." % category ) # Check for dropdown (multiple choropleth plots via dropdown selection): if dropdown is None: pass elif not isinstance(dropdown, (list, tuple)): raise ValueError( "For <dropdown>, please provide a list/tuple of existing columns of the GeoDataFrame." ) else: for col in dropdown: if col not in gdf.columns: raise ValueError( "Could not find column '%s' for <dropdown> in GeoDataFrame. " % col ) # Check for slider (multiple choropleth plots via slider selection): if slider is None: pass elif not isinstance(slider, (list, tuple)): raise ValueError( "For <slider>, please provide a list/tuple of existing columns of the GeoDataFrame." ) else: for col in slider: if col not in gdf.columns: raise ValueError( "Could not find column '%s' for <slider> in GeoDataFrame. " % col ) if not slider_range is None: if not isinstance(slider_range, Iterable): raise ValueError( "<slider_range> has to be a type that is iterable like list, tuple, range, ..." ) else: slider_range = list(slider_range) if len(slider_range) != len(slider): raise ValueError( "The number of elements in <slider_range> has to be the same as in <slider>." ) steps = [] for i in range(len(slider_range) - 1): steps.append(slider_range[i + 1] - slider_range[i]) if len(set(steps)) > 1: raise ValueError( "<slider_range> has to have equal step size between each elements (like a range-object)." ) else: slider_step = steps[0] slider_start = slider_range[0] slider_end = slider_range[-1] # Check colormap if either <category>, <dropdown> or <slider> is choosen: if category_options == 1: if colormap is None: colormap = blue_colormap elif isinstance(colormap, (tuple, list)): if len(colormap) > 1: pass else: raise ValueError( "<colormap> only accepts a list/tuple of at least two colors or the name of one of the following predefined colormaps (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (list(all_palettes.keys())) ) elif isinstance(colormap, str): if colormap in all_palettes: colormap = all_palettes[colormap] colormap = colormap[max(colormap.keys())] else: raise ValueError( "Could not find <colormap> with name %s. The following predefined colormaps are supported (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (colormap, list(all_palettes.keys())) ) else: raise ValueError( "<colormap> only accepts a list/tuple of at least two colors or the name of one of the following predefined colormaps (see also https://bokeh.pydata.org/en/latest/docs/reference/palettes.html ): %s" % (list(all_palettes.keys())) ) else: if isinstance(color, str): colormap = [color] elif color is None: colormap = ["blue"] else: raise ValueError( "<color> has to be a string specifying the fill_color of the map glyph." ) # Check xlim & ylim: if xlim is not None: if isinstance(xlim, (tuple, list)): if len(xlim) == 2: from pyproj import Proj, transform inProj = Proj(init="epsg:4326") outProj = Proj(init="epsg:3857") xmin, xmax = xlim for _ in [xmin, xmax]: if not -180 < _ <= 180: raise ValueError( "Limits for x-axis (=Longitude) have to be between -180 and 180." ) if not xmin < xmax: raise ValueError("xmin has to be smaller than xmax.") xmin = transform(inProj, outProj, xmin, 0)[0] xmax = transform(inProj, outProj, xmax, 0)[0] figure_options["x_range"] = (xmin, xmax) else: raise ValueError( "Limits for x-axis (=Longitude) have to be of form [xmin, xmax] with values between -180 and 180." ) else: raise ValueError( "Limits for x-axis (=Longitude) have to be of form [xmin, xmax] with values between -180 and 180." ) if ylim is not None: if isinstance(ylim, (tuple, list)): if len(ylim) == 2: from pyproj import Proj, transform inProj = Proj(init="epsg:4326") outProj = Proj(init="epsg:3857") ymin, ymax = ylim for _ in [ymin, ymax]: if not -90 < _ <= 90: raise ValueError( "Limits for y-axis (=Latitude) have to be between -90 and 90." ) if not ymin < ymax: raise ValueError("ymin has to be smaller than ymax.") ymin = transform(inProj, outProj, 0, ymin)[1] ymax = transform(inProj, outProj, 0, ymax)[1] figure_options["y_range"] = (ymin, ymax) else: raise ValueError( "Limits for y-axis (=Latitude) have to be of form [ymin, ymax] with values between -90 and 90." ) else: raise ValueError( "Limits for y-axis (=Latitude) have to be of form [ymin, ymax] with values between -90 and 90." ) # Create Figure to draw: old_layout = None if figure is None: p = bokeh.plotting.figure(**figure_options) # Add Tile Source as Background: p = _add_backgroundtile( p, tile_provider, tile_provider_url, tile_attribution, tile_alpha ) elif isinstance(figure, type(bokeh.plotting.figure())): p = figure elif isinstance(figure, type(column())): old_layout = figure p = _get_figure(old_layout) else: raise ValueError( "Parameter <figure> has to be of type bokeh.plotting.figure or bokeh.layouts.column." ) # Get ridd of zoom on axes: for t in p.tools: if type(t) == WheelZoomTool: t.zoom_on_axis = False # Hide legend if wanted: legend_input = legend if isinstance(legend, str): pass else: legend = "GeoLayer" # Define colormapper: if len(colormap) == 1: kwargs["fill_color"] = colormap[0] elif not category is None: # Check if category column is numerical: if not issubclass(gdf[category].dtype.type, np.number): raise NotImplementedError( "<category> plot only yet implemented for numerical columns. Column '%s' is not numerical." % category ) field = category colormapper_options = {"palette": colormap} if not colormap_range is None: if not isinstance(colormap_range, (tuple, list)): raise ValueError( "<colormap_range> can only be 'None' or a tuple/list of form (min, max)." ) elif len(colormap_range) == 2: colormapper_options["low"] = colormap_range[0] colormapper_options["high"] = colormap_range[1] else: colormapper_options["low"] = gdf[field].min() colormapper_options["high"] = gdf[field].max() if colormap_uselog: colormapper = LogColorMapper(**colormapper_options) else: colormapper = LinearColorMapper(**colormapper_options) kwargs["fill_color"] = {"field": "Colormap", "transform": colormapper} if not isinstance(legend, str): legend = str(field) elif not dropdown is None: # Check if all columns in dropdown selection are numerical: for col in dropdown: if not issubclass(gdf[col].dtype.type, np.number): raise NotImplementedError( "<dropdown> plot only yet implemented for numerical columns. Column '%s' is not numerical." % col ) field = dropdown[0] colormapper_options = {"palette": colormap} if not colormap_range is None: if not isinstance(colormap_range, (tuple, list)): raise ValueError( "<colormap_range> can only be 'None' or a tuple/list of form (min, max)." ) elif len(colormap_range) == 2: colormapper_options["low"] = colormap_range[0] colormapper_options["high"] = colormap_range[1] else: colormapper_options["low"] = gdf[dropdown].min().min() colormapper_options["high"] = gdf[dropdown].max().max() if colormap_uselog: colormapper = LogColorMapper(**colormapper_options) else: colormapper = LinearColorMapper(**colormapper_options) kwargs["fill_color"] = {"field": "Colormap", "transform": colormapper} legend = " " + field elif not slider is None: # Check if all columns in dropdown selection are numerical: for col in slider: if not issubclass(gdf[col].dtype.type, np.number): raise NotImplementedError( "<slider> plot only yet implemented for numerical columns. Column '%s' is not numerical." % col ) field = slider[0] colormapper_options = {"palette": colormap} if not colormap_range is None: if not isinstance(colormap_range, (tuple, list)): raise ValueError( "<colormap_range> can only be 'None' or a tuple/list of form (min, max)." ) elif len(colormap_range) == 2: colormapper_options["low"] = colormap_range[0] colormapper_options["high"] = colormap_range[1] else: colormapper_options["low"] = gdf[slider].min().min() colormapper_options["high"] = gdf[slider].max().max() if colormap_uselog: colormapper = LogColorMapper(**colormapper_options) else: colormapper = LinearColorMapper(**colormapper_options) kwargs["fill_color"] = {"field": "Colormap", "transform": colormapper} if not isinstance(legend, str): legend = "Geolayer" # Check that only hovertool_columns or hovertool_string is used: if isinstance(hovertool_columns, (list, tuple, str)): if len(hovertool_columns) > 0 and hovertool_string is not None: raise ValueError( "Either <hovertool_columns> or <hovertool_string> can be used, but not both at the same time." ) else: raise ValueError( "<hovertool_columns> has to be a list of columns of the GeoDataFrame or the string 'all'." ) if hovertool_string is not None: hovertool_columns = "all" # Check for Hovertool columns: if hovertool: if not isinstance(hovertool_columns, (list, tuple)): if hovertool_columns == "all": hovertool_columns = list( filter(lambda col: col != "geometry", gdf.columns) ) else: raise ValueError( "<hovertool_columns> has to be a list of columns of the GeoDataFrame or the string 'all'." ) elif len(hovertool_columns) == 0: if not category is None: hovertool_columns = [category] elif not dropdown is None: hovertool_columns = dropdown elif not slider is None: hovertool_columns = slider else: hovertool_columns = [] else: for col in hovertool_columns: if col not in gdf.columns: raise ValueError( "Could not find columns '%s' in GeoDataFrame. <hovertool_columns> has to be a list of columns of the GeoDataFrame or the string 'all'." % col ) else: if category is None: hovertool_columns = [] else: hovertool_columns = [category] # Reduce DataFrame to needed columns: if type(gdf) == pd.DataFrame: gdf["Geometry"] = 0 additional_columns = ["x", "y"] else: additional_columns = ["geometry"] for kwarg, value in kwargs.items(): if isinstance(value, Hashable): if value in gdf.columns: additional_columns.append(value) if category_options == 0: gdf = gdf[list(set(hovertool_columns) | set(additional_columns))] else: gdf = gdf[ list( set(hovertool_columns) | set(category_columns) | set(additional_columns) ) ] gdf["Colormap"] = gdf[field] field = "Colormap" # Create GeoJSON DataSource for Plot: if type(gdf) != pd.DataFrame: geo_source = GeoJSONDataSource(geojson=gdf.to_json()) else: geo_source = gdf # Draw Glyph on Figure: layout = None if "Point" in layertypes: if "line_color" not in kwargs: kwargs["line_color"] = kwargs["fill_color"] glyph = p.scatter(x="x", y="y", source=geo_source, legend=legend, **kwargs) if "Line" in layertypes: if "line_color" not in kwargs: kwargs["line_color"] = kwargs["fill_color"] del kwargs["fill_color"] glyph = p.multi_line( xs="xs", ys="ys", source=geo_source, legend=legend, **kwargs ) if "Polygon" in layertypes: if "line_color" not in kwargs: kwargs["line_color"] = "black" # Creates from a geoDataFrame with Polygons and Multipolygons a Pandas DataFrame # with x any y columns specifying the geometry of the Polygons: geo_source = ColumnDataSource(convert_geoDataFrame_to_patches(gdf)) # Plot polygons: glyph = p.multi_polygons( xs="__x__", ys="__y__", source=geo_source, legend=legend, **kwargs ) # Add hovertool: if hovertool and (category_options == 1 or len(hovertool_columns) > 0): my_hover = HoverTool(renderers=[glyph]) if hovertool_string is None: my_hover.tooltips = [(str(col), "@{%s}" % col) for col in hovertool_columns] else: my_hover.tooltips = hovertool_string p.add_tools(my_hover) # Add colorbar: if show_colorbar and category_options == 1: colorbar_options = { "color_mapper": colormapper, "label_standoff": 12, "border_line_color": None, "location": (0, 0), } if colormap_uselog: colorbar_options["ticker"] = LogTicker() if colorbar_tick_format: colorbar_options["formatter"] = get_tick_formatter(colorbar_tick_format) colorbar = ColorBar(**colorbar_options) p.add_layout(colorbar, "right") # Add Dropdown Widget: if not dropdown is None: # Define Dropdown widget: dropdown_widget = Dropdown( label="Select Choropleth Layer", menu=list(zip(dropdown, dropdown)) ) # Define Callback for Dropdown widget: callback = CustomJS( args=dict( dropdown_widget=dropdown_widget, geo_source=geo_source, legend=p.legend[0].items[0], ), code=""" //Change selection of field for Colormapper for choropleth plot: geo_source.data["Colormap"] = geo_source.data[dropdown_widget.value]; geo_source.change.emit(); //Change label of Legend: legend.label["value"] = " " + dropdown_widget.value; """, ) dropdown_widget.js_on_change("value", callback) # Add Dropdown widget above the plot: if old_layout is None: layout = column(dropdown_widget, p) else: layout = column(dropdown_widget, old_layout) # Add Slider Widget: if not slider is None: if slider_range is None: slider_start = 0 slider_end = len(slider) - 1 slider_step = 1 value2name = ColumnDataSource( { "Values": np.arange( slider_start, slider_end + slider_step, slider_step ), "Names": slider, } ) # Define Slider widget: slider_widget = Slider( start=slider_start, end=slider_end, value=slider_start, step=slider_step, title=slider_name, ) # Define Callback for Slider widget: callback = CustomJS( args=dict( slider_widget=slider_widget, geo_source=geo_source, value2name=value2name, ), code=""" //Change selection of field for Colormapper for choropleth plot: var slider_value = slider_widget.value; for(i=0; i<value2name.data["Names"].length; i++) { if (value2name.data["Values"][i] == slider_value) { var name = value2name.data["Names"][i]; } } geo_source.data["Colormap"] = geo_source.data[name]; geo_source.change.emit(); """, ) slider_widget.js_on_change("value", callback) # Add Slider widget above the plot: if old_layout is None: layout = column(slider_widget, p) else: layout = column(slider_widget, old_layout) # Hide legend if user wants: if legend_input is False: p.legend.visible = False # Set click policy for legend: p.legend.click_policy = "hide" # Set panning option: if panning is False: p.toolbar.active_drag = None # Set zooming option: if zooming is False: p.toolbar.active_scroll = None # Display plot and if wanted return plot: if layout is None: if old_layout is None: layout = p else: layout = old_layout # Display plot if wanted if show_figure: show(layout) # Return as (embeddable) HTML if wanted: if return_html: return embedded_html(layout) # Return plot: if return_figure: return layout
def index(): state_xs = pickle.load(open("state_xs.pck", "rb")) state_ys = pickle.load(open("state_ys.pck", "rb")) state_names = pickle.load(open("state_names.pck", "rb")) state_rates = pickle.load(open("state_rates.pck", "rb")) state_clusters = pickle.load(open("state_clusters.pck", "rb")) cluster_label = pickle.load(open("cluster_label.pck", "rb")) slope_pay_per_case = pickle.load(open("slope_per_case.pck", "rb")) slope_count_per_1000000 = pickle.load( open("slope_count_per_1000000.pck", "rb")) slope_total_pay = pickle.load(open("slope_total_pay.pck", "rb")) color_mapper = LinearColorMapper(palette=palette) color_mapper = LinearColorMapper( palette=palette ) #, low=min(slope_count_per_1000000), high=max(slope_count_per_1000000)) source = ColumnDataSource(data=dict( x=state_xs, y=state_ys, name=state_names, clusters=state_clusters, cluster_label=cluster_label, slopes1=slope_pay_per_case, slopes2=slope_count_per_1000000, slopes3=slope_total_pay, )) TOOLS = "pan,wheel_zoom,reset,hover,save" p = figure( #title="Change in the number of malpractice cases filed per a million citizens per states, 1990-2018", plot_width=int( (max(max(state_xs)) - min(min(state_xs))) * lon_inkm / 4.5), plot_height=int( (max(max(state_ys)) - min(min(state_ys))) * lat_inkm / 4.5), tools=TOOLS, x_axis_location=None, y_axis_location=None) p.grid.grid_line_color = None mypatches = p.patches('x', 'y', source=source, fill_color={ 'field': 'slopes2', 'transform': color_mapper }, fill_alpha=0.7, line_color="gray", line_width=0.5) color_bar = ColorBar(color_mapper=color_mapper, ticker=BasicTicker(), label_standoff=12, border_line_color=None, location=(0, 0), major_label_text_font_size="14pt") p.add_layout(color_bar, 'right') #HoverTool(tooltips=None, callback=callback, renderers=[cr]) hover = p.select_one( HoverTool) #(tooltips=None, callback=callback, renderers=[mypatches])) hover.point_policy = "follow_mouse" hover.tooltips = """ <font size="3">State: <strong>@name</strong> </font> <br> <font size="3">Average changes over the last 27 years in...</font> <br> <font size="3">...mean state payout: <strong>$@slopes1 </strong> </font> <br> <font size="3">...number of cases/mil: <strong>@slopes2 cases per million</strong> </font> <br> <font size="3">...total state payout: <strong>$@slopes3</strong> </font> <br> """ #output_notebook() callback = CustomJS(args=dict(source=source, patches=mypatches), code=""" var selected_slopes = cb_obj.value; patches.glyph.fill_color.field = selected_slopes; source.change.emit(); """) menu = [("mean state payout ($)", "slopes1"), ("number of cases per million", "slopes2"), ("total state payout ($)", "slopes3")] dropdown = Dropdown(menu=menu, label="Select option to see change in...", button_type="danger") dropdown.js_on_change('value', callback) layout_ = column(children=[dropdown, p], sizing_mode='fixed') script, div = components(layout_) #print script return render_template('index.html', script=script, div=div)
class SequencePathWidget: "Dropdown for choosing a fasta file" _dialog: FileDialog _widget: Dropdown _theme: SequencePathTheme _model: SequencePlotModelAccess def __init__(self, ctrl, **kwa): self._theme = ctrl.theme.swapmodels(SequencePathTheme(**kwa)) self._model = SequencePlotModelAccess() self._model.swapmodels(ctrl) def addtodoc(self, mainview, ctrl, *_) -> List[Widget]: "creates the widget" self._widget = Dropdown(name='Cycles:Sequence', width=self._theme.width, height=self._theme.height, **self._data()) mainview.differedobserver(self._data, self._widget, ctrl.theme, self._model.sequencemodel.config, ctrl.display, self._model.sequencemodel.display) self._widget.on_click(ctrl.action(self._onclick)) return [self._widget] def observe(self, ctrl): "sets-up config observers" self._dialog = FileDialog(ctrl, storage="sequence", title=self._theme.dlgtitle, filetypes='fasta|txt|*') def reset(self, resets): "updates the widget" resets[self._widget].update(**self._data()) @property def widget(self): "returns the widget" return self._widget def callbacks(self, hover: SequenceHoverMixin, tick1: SequenceTicker): "sets-up callbacks for the tooltips and grids" if hover is not None: jsc = CustomJS( code=("if(Object.keys(src.data).indexOf(cb_obj.value) > -1)" "{ cb_obj.label = cb_obj.value;" " tick1.key = cb_obj.value;" " tick2.key = cb_obj.value;" " src.data['text'] = src.data[cb_obj.value];" " src.change.emit(); }"), args=dict(tick1=tick1, tick2=tick1.axis, src=hover.source)) self._widget.js_on_change('value', jsc) return self._widget def _data(self) -> dict: lst = sorted(self._model.sequences(...)) key = self._model.sequencemodel.currentkey val = key if key in lst else None label = self._theme.missingkey if val is None else key menu: List[Optional[Tuple[str, str]]] = [(i, i) for i in lst] menu += [ None if len(menu) else ('', '→'), (self._theme.missingpath, '←') ] return dict(menu=menu, label=label, value='→' if val is None else val) def _onclick(self, new): if new.item == '←': path = self._dialog.open() self._widget.value = '→' if self._model.setnewsequencepath(path): if path is not None: raise IOError("Could not find any sequence in the file") elif new.item != '→': self._model.setnewsequencekey(new.item)
post_rend = pcut_ax.multi_line('xs', 'ys', source=post_blank, line_width=2, color='c', alpha='alpha') hover = HoverTool(renderers=[sequence], callback=js_cbs[1], tooltips=[('mutation', '@display_name'), ('number of beads', '@n_beads'), ('number of loops', '@n_loops'), ('number of cuts', '@n_cuts')]) seq_ax.add_tools(hover) sel.js_on_change('value', js_cbs[0]) spacer = Div(text='<br/>') sel_col = bokeh.layouts.column(sel, seq_ax) freq_col = bokeh.layouts.column(bar_ax, loop_freq_ax) cut_col = bokeh.layouts.column(spacer, pcut_ax) dwell_row = bokeh.layouts.row(leg_ax, dwell_unloop_ax, dwell_cut_ax, dwell_all_ax) row1 = bokeh.layouts.row(freq_col, cut_col) col1 = bokeh.layouts.column(row1, dwell_row) lay = bokeh.layouts.column(sel_col, col1) # Set the theme. theme_json = {