Example #1
0
    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()
Example #2
0
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))
Example #3
0
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
Example #4
0
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
Example #5
0
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)
Example #6
0
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 = {