├── MANIFEST.in ├── examples ├── requirements.txt └── streamlit_app.py ├── .github ├── FUNDING.yml └── workflows │ └── update_pypi_on_new_tag.yml ├── _static └── simple_example.png ├── .gitignore ├── setup.py ├── LICENSE ├── README.md └── streamlit_letsplot └── __init__.py /MANIFEST.in: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/requirements.txt: -------------------------------------------------------------------------------- 1 | streamlit >= 1.2 2 | streamlit-letsplot 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: randyzwitch 4 | -------------------------------------------------------------------------------- /_static/simple_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/randyzwitch/streamlit-letsplot/HEAD/_static/simple_example.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | yarn.lock 8 | 9 | # testing 10 | coverage 11 | 12 | # production 13 | build 14 | dist 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | src/frontend/node_modules/ 28 | .vscode 29 | node_modules/ 30 | *.egg-info 31 | __pycache__ -------------------------------------------------------------------------------- /examples/streamlit_app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | from streamlit_letsplot import st_letsplot 3 | 4 | 5 | import numpy as np 6 | import lets_plot 7 | from lets_plot import * 8 | 9 | np.random.seed(12) 10 | data = dict( 11 | cond=np.repeat(['A','B'], 200), 12 | rating=np.concatenate((np.random.normal(0, 1, 200), np.random.normal(1, 1.5, 200))) 13 | ) 14 | 15 | a = ggplot(data, aes(x='rating', fill='cond')) + ggsize(500, 250) \ 16 | + geom_density(color='dark_green', alpha=.7) + scale_fill_brewer(type='seq') \ 17 | + theme(axis_line_y='blank') 18 | 19 | st_letsplot(a) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | setuptools.setup( 4 | name="streamlit-letsplot", 5 | version="0.0.3", 6 | author="Randy Zwitch", 7 | author_email="randy@streamlit.io", 8 | description="Streamlit component for Lets Plot visualization library", 9 | long_description="Streamlit component for Lets Plot visualization library", 10 | long_description_content_type="text/plain", 11 | url="https://github.com/randyzwitch/streamlit-letsplot", 12 | packages=setuptools.find_packages(), 13 | include_package_data=True, 14 | classifiers=[], 15 | python_requires=">=3.6", 16 | install_requires=["streamlit >= 0.63", "lets-plot >= 2.0.0"], 17 | ) 18 | -------------------------------------------------------------------------------- /.github/workflows/update_pypi_on_new_tag.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install setuptools wheel twine 25 | - name: Build and publish 26 | env: 27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 29 | run: | 30 | python setup.py sdist bdist_wheel 31 | twine upload dist/* 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Randy Zwitch 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # streamlit-letsplot 2 | 3 | [![Streamlit App](https://static.streamlit.io/badges/streamlit_badge_black_white.svg)](https://share.streamlit.io/randyzwitch/streamlit-letsplot/examples/streamlit_app.py) 4 | 5 | 6 | This is a work-in-progress, providing a convenience function to plot charts from the [Lets-Plot](https://lets-plot.org/) visualization library. 7 | 8 | ## Example usage 9 | 10 | ```python 11 | import streamlit as st 12 | from streamlit_letsplot import st_letsplot 13 | import numpy as np 14 | import lets_plot 15 | from lets_plot import * 16 | 17 | np.random.seed(12) 18 | data = dict( 19 | cond=np.repeat(['A','B'], 200), 20 | rating=np.concatenate((np.random.normal(0, 1, 200), np.random.normal(1, 1.5, 200))) 21 | ) 22 | 23 | a = ggplot(data, aes(x='rating', fill='cond')) + ggsize(500, 250) \ 24 | + geom_density(color='dark_green', alpha=.7) + scale_fill_brewer(type='seq') \ 25 | + theme(axis_line_y='blank') 26 | 27 | # plots any Let's Plot visualization object 28 | st_letsplot(a) 29 | ``` 30 | 31 | ![st_letsplot](https://github.com/randyzwitch/streamlit-letsplot/blob/master/_static/simple_example.png) 32 | -------------------------------------------------------------------------------- /streamlit_letsplot/__init__.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | import streamlit.components.v1 as components 3 | from lets_plot.frontend_context._configuration import _as_html 4 | from lets_plot.plot.core import PlotSpec 5 | from lets_plot.plot.plot import GGBunch 6 | 7 | def st_letsplot(plot, scrolling=True): 8 | """Embed a Let's Plot object within Streamlit app 9 | 10 | Parameters 11 | ---------- 12 | plot: 13 | Let's Plot object 14 | scrolling: bool 15 | If content is larger than iframe size, provide scrollbars? 16 | 17 | Example 18 | ------- 19 | >>> st_letsplot(p) 20 | """ 21 | 22 | plot_dict = plot.as_dict() 23 | if isinstance(plot, PlotSpec): 24 | width, height = get_ggsize_or_default(plot_dict, default=500) 25 | elif isinstance(plot, GGBunch): 26 | # the inner list comprehension is a list of (width, height) tuples 27 | # the outer consists of two elements [sum(widths), sum(heights)] 28 | width, height = [sum(y) for y in zip(*[get_ggsize_or_default(x["feature_spec"], default=500) for x in plot_dict["items"]])] 29 | else: 30 | height=500 31 | width=500 32 | 33 | # 20 an aribtrary pad to remove scrollbars from iframe, consider if worth removing 34 | return components.html(_as_html(plot_dict), 35 | height=height + 20, 36 | width=width + 20, 37 | scrolling=scrolling, 38 | ) 39 | 40 | def get_ggsize_or_default(plot_dict, default=500) -> (int, int): 41 | """ 42 | Returns a tuple consisting of the width and height of the plot 43 | Lookup if there is a ggsize specification. If not return default value. 44 | :param plot_dict: 45 | :param default: 46 | :return: width, height 47 | """ 48 | if 'ggsize' in plot_dict.keys(): 49 | return plot_dict["ggsize"]["width"], plot_dict["ggsize"]["height"] 50 | return default, default 51 | --------------------------------------------------------------------------------