-
Notifications
You must be signed in to change notification settings - Fork 2
Implementation of Bokeh Chart Custom Component #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
c2b0c60
to
5e55e69
Compare
setup.py
Outdated
|
||
setuptools.setup( | ||
name="streamlit-bokeh", | ||
version="3.6.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just sanity-check: was your idea to follow the bokeh versioning? So when bokeh is updated, we also bump this version to the same one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the current plan. But I am reconsidering it now if there's a issue and we need to issue a patch. Let me think a little bit more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point, I think it might make sense to use our own versioning. Not only for patches, but perhaps we change something with the (internal) API or whatever and then we might run into issues. So decoupling the versions might make sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could try to match only the major and minor versions of bokeh and keep the patch version for ourselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that. Will adjust to 3.6.0
setup.py
Outdated
# By definition, a Custom Component depends on Streamlit. | ||
# If your component has other Python dependencies, list | ||
# them here. | ||
"streamlit >= 0.63", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering whether we should be way more strict. While technical apparently possible, would we really want to enable such an old version to work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would help with adoptability, but we can also try doing 1.26.0+ for partners' sake?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot re-use the font files that already come bundled with Streamlit because we are in an iframe, can we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The answer is yes unfortunately. We could hard code the parent frame's URL which enables caching, but that would be more brittle should Streamlit adjust the location and naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too bad! I agree, the alternative sounds too brittle!
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>Streamlit Component</title> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: better title might a "Streamlit Bokeh Chart"
// embed_item is actually an async function call, so a race condition | ||
// can occur if updateChart is called twice, leading to two Bokeh charts | ||
// to be embedded at the same time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but this cannot happen here because we use await
? Should we have a lock or something indicating that the function was called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, we can probably remove the comment now.
const renderedAppTheme = JSON.stringify(renderData.theme) | ||
|
||
let themeChanged = false | ||
if ( | ||
renderData.args.bokeh_theme !== currentTheme || | ||
appTheme !== renderedAppTheme | ||
) { | ||
currentTheme = renderData.args.bokeh_theme |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you elaborate a little bit please why there are two ways of passing a theme to the chart? renderData.args.bokeh_theme
seems to come from the Python side, right? Where does renderData.theme
come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renderData.theme
is the theme that comes from Streamlit (so if I switch light theme to dark theme) renderData.theme
changes. I probably should make this more efficient and specify if the bokeh theme changed or the bokeh theme is "streamlit"
and the rendered theme has changed. I'll fix that.
if (currentTheme === "streamlit") { | ||
use_theme(streamlitTheme(renderData.theme as Theme)) | ||
themeChanged = true | ||
} else if (currentTheme in window.Bokeh.Themes) { | ||
use_theme(window.Bokeh.Themes[currentTheme]) | ||
} else { | ||
use_theme(streamlitTheme(renderData.theme as Theme)) | ||
themeChanged = true | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would change this to:
if (currentTheme === "streamlit" || !(currentTheme in window.Bokeh.Themes)) {
use_theme(streamlitTheme(renderData.theme as Theme))
themeChanged = true
} else {
use_theme(window.Bokeh.Themes[currentTheme])
}
In my opinion this makes it more obvious that the first and third case perform the identical operation.
// Python script. | ||
|
||
// We tell Streamlit to update our frameHeight after each render event, in | ||
// case it has changed. (This isn't strictly necessary for the example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still, why not move it into the if(hasChanged || themeChanged)
block?
if ( | ||
renderData.args.bokeh_theme !== currentTheme || | ||
appTheme !== renderedAppTheme | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: it might be cleaner to move the theme logic to its own function so that onRender
is more dense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the file be removed?
Also, was the idea to not use React to have one dependency less we have to maintain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll check. It came from the template, so I assumed it was necessary. And yes. Since Bokeh doesn't come in a nice react component, and we do minimal processing. I figured it was simpler to just use vanilla JS. Should be faster.
} | ||
|
||
export function streamlitTheme(theme: Theme): BokehTheme { | ||
// @ts-expect-error fadedText10 is not defined in the Theme type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its not defined, but set by our streamlit-component-lib? In this case, instead of expecting this error, perhaps this should be fixed in the Theme
of streamlit-component-lib
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll double check with @sfc-gh-lmasuch since this is tied to the advanced theming (also a note to make sure the advanced theming is included in the minimum version we require.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah, checking the minimal version is a good aspect!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think we eventually need to officially expose colors that are generated from theme variables as well to custom components. But not sure if fadedText10
will be something that stays forever. Maybe its a bit safer to actually create this color manually here: transparentize(textColor, 0.8)
. fadedText10
is something that could be removed at any time -> which probably will break this custom component
"resolveJsonModule": true, | ||
"isolatedModules": true, | ||
"noEmit": true, | ||
"jsx": "react" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we don't seem to use React in this repo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you feel about adding a couple of unit tests for the functions in index.ts
(getChartData
(and the fact that it is memoized), an extracted processTheme
function, ...) ? I know you have added e2e tests in #6, but for fast and general testing it could make test.
streamlit_bokeh/__init__.py
Outdated
if TYPE_CHECKING: | ||
from bokeh.plotting.figure import Figure | ||
|
||
ST_BOKEH_VERSION = importlib.metadata.version("streamlit_bokeh") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: should we also expose this under __version__
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will make this version. Though with the new convention, I opted to hard code the dependency version for simplicity. The update script will update everything.
streamlit_bokeh/__init__.py
Outdated
|
||
ST_BOKEH_VERSION = importlib.metadata.version("streamlit_bokeh") | ||
|
||
def streamlit_bokeh(figure: "Figure", use_container_width=True, theme: str = "streamlit", key=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the types of use_container_width
and key
+ the return type is missing here
setup.py
Outdated
packages=setuptools.find_packages(), | ||
include_package_data=True, | ||
classifiers=[], | ||
python_requires=">=3.10", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: is it also possible to support python 3.9 since this is also still supported with Streamlit?
@@ -1,2 +1,3 @@ | |||
# streamlit-bokeh-chart | |||
# streamlit-bokeh | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we might want to add a bit more info here, but that's probably a follow up or something to get Debbie involved in.
// See https://github.com/bokeh/bokeh/blob/3.6.2/bokehjs/src/lib/models/plots/plot.ts#L203 | ||
const DEFAULT_WIDTH = 600 // px | ||
const DEFAULT_HEIGHT = 600 // px |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The default width & height we use for vega charts is 400 x 350 (not sure about plotly). No strong opinion, but maybe it makes sense to use similar numbers for bokeh.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 added a couple of minor comments.
Two changes that might be worth doing:
|
This PR intrroduces the bokeh chart in its entirety for release.
We are deliberately releasing 3.6.1 in order to test out the auto update functionality.
The component is simple avoiding react and making it a pure JS app.
Recommendation to Reviewers: Feel free to give format suggestions, though the next PR #5 focuses on the formatting fixes.