|
| 1 | +import os |
| 2 | +import streamlit.components.v1 as components |
| 3 | + |
| 4 | +# Create a _RELEASE constant. We'll set this to False while we're developing |
| 5 | +# the component, and True when we're ready to package and distribute it. |
| 6 | +# (This is, of course, optional - there are innumerable ways to manage your |
| 7 | +# release process.) |
| 8 | +_DEV = os.environ.get("DEV", False) |
| 9 | +_RELEASE = not _DEV |
| 10 | + |
| 11 | +# Declare a Streamlit component. `declare_component` returns a function |
| 12 | +# that is used to create instances of the component. We're naming this |
| 13 | +# function "_component_func", with an underscore prefix, because we don't want |
| 14 | +# to expose it directly to users. Instead, we will create a custom wrapper |
| 15 | +# function, below, that will serve as our component's public API. |
| 16 | + |
| 17 | +# It's worth noting that this call to `declare_component` is the |
| 18 | +# *only thing* you need to do to create the binding between Streamlit and |
| 19 | +# your component frontend. Everything else we do in this file is simply a |
| 20 | +# best practice. |
| 21 | + |
| 22 | +if not _RELEASE: |
| 23 | + _component_func = components.declare_component( |
| 24 | + # We give the component a simple, descriptive name ("streamlit_bokeh" |
| 25 | + # does not fit this bill, so please choose something better for your |
| 26 | + # own component :) |
| 27 | + "streamlit_bokeh", |
| 28 | + # Pass `url` here to tell Streamlit that the component will be served |
| 29 | + # by the local dev server that you run via `npm run start`. |
| 30 | + # (This is useful while your component is in development.) |
| 31 | + url="http://localhost:3001", |
| 32 | + ) |
| 33 | +else: |
| 34 | + # When we're distributing a production version of the component, we'll |
| 35 | + # replace the `url` param with `path`, and point it to the component's |
| 36 | + # build directory: |
| 37 | + parent_dir = os.path.dirname(os.path.abspath(__file__)) |
| 38 | + build_dir = os.path.join(parent_dir, "frontend/build") |
| 39 | + _component_func = components.declare_component("streamlit_bokeh", path=build_dir) |
| 40 | + |
| 41 | + |
| 42 | +import importlib.metadata |
| 43 | +from typing import TYPE_CHECKING |
| 44 | +import bokeh |
| 45 | +from bokeh.embed import json_item |
| 46 | +import json |
| 47 | + |
| 48 | +if TYPE_CHECKING: |
| 49 | + from bokeh.plotting.figure import Figure |
| 50 | + |
| 51 | +ST_BOKEH_VERSION = importlib.metadata.version("streamlit_bokeh") |
| 52 | + |
| 53 | +def streamlit_bokeh(figure: "Figure", use_container_width=True, theme: str = "streamlit", key=None): |
| 54 | + """Create a new instance of "streamlit_bokeh". |
| 55 | +
|
| 56 | + Parameters |
| 57 | + ---------- |
| 58 | + figure: bokeh.plotting.figure.Figure |
| 59 | + A Bokeh figure to plot. |
| 60 | + use_container_width : bool |
| 61 | + Whether to override the figure's native width with the width of |
| 62 | + the parent container. If ``use_container_width`` is ``False``, |
| 63 | + Streamlit sets the width of the chart to fit its contents |
| 64 | + according to the plotting library, up to the width of the parent |
| 65 | + container. If ``use_container_width`` is ``True`` (default), Streamlit |
| 66 | + sets the width of the figure to match the width of the parent container. |
| 67 | + key: str or None |
| 68 | + An optional key that uniquely identifies this component. If this is |
| 69 | + None, and the component's arguments are changed, the component will |
| 70 | + be re-mounted in the Streamlit frontend and lose its current state. |
| 71 | +
|
| 72 | + Example |
| 73 | + ------- |
| 74 | + >>> from streamlit_bokeh import streamlit_bokeh |
| 75 | + >>> from bokeh.plotting import figure |
| 76 | + >>> |
| 77 | + >>> x = [1, 2, 3, 4, 5] |
| 78 | + >>> y = [6, 7, 2, 4, 5] |
| 79 | + >>> |
| 80 | + >>> p = figure(title="simple line example", x_axis_label="x", y_axis_label="y") |
| 81 | + >>> p.line(x, y, legend_label="Trend", line_width=2) |
| 82 | + >>> |
| 83 | + >>> streamlit_bokeh(p, use_container_width=True) |
| 84 | +
|
| 85 | + """ |
| 86 | + |
| 87 | + if bokeh.__version__ != ST_BOKEH_VERSION: |
| 88 | + # TODO(ken): Update Error message |
| 89 | + raise Exception( |
| 90 | + f"Streamlit only supports Bokeh version {ST_BOKEH_VERSION}, " |
| 91 | + f"but you have version {bokeh.__version__} installed. Please " |
| 92 | + f"run `pip install --force-reinstall --no-deps bokeh==" |
| 93 | + f"{ST_BOKEH_VERSION}` to install the correct version." |
| 94 | + ) |
| 95 | + |
| 96 | + # Call through to our private component function. Arguments we pass here |
| 97 | + # will be sent to the frontend, where they'll be available in an "args" |
| 98 | + # dictionary. |
| 99 | + component_value = _component_func( |
| 100 | + figure=json.dumps(json_item(figure)), |
| 101 | + use_container_width=use_container_width, |
| 102 | + bokeh_theme=theme, |
| 103 | + key=key) |
| 104 | + |
| 105 | + # We could modify the value returned from the component if we wanted. |
| 106 | + # There's no need to do this in our simple example - but it's an option. |
| 107 | + return component_value |
0 commit comments