From 9eda4a57fadf38910bca8b5445a37c75bcadfca8 Mon Sep 17 00:00:00 2001 From: nicolalandro Date: Sun, 21 Nov 2021 14:03:30 +0100 Subject: [PATCH] add new examples for jupyter and streamlit --- README.md | 20 +++- examples/jupyter_example.ipynb | 189 +++++++++++++++++++++++++++++++++ examples/stramlit_example.py | 10 ++ imgs/streamlit_example.png | Bin 0 -> 15357 bytes 4 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 examples/jupyter_example.ipynb create mode 100644 examples/stramlit_example.py create mode 100644 imgs/streamlit_example.png diff --git a/README.md b/README.md index c9e8c22..49b32ad 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Install with `pip install obj2html` and use with `obj2html('model.obj', 'index.h ![](imgs/colab_sample.png) -* run into jupyter notebook +* run into [jupyter notebook](https://jupyter.org/) ([jupyter_example.ipynb](examples/jupyter_example.ipynb)): ``` ! pip install obj2html ! wget https://gitlab.com/nicolalandro/obj2html/-/raw/main/test/assets/model.obj @@ -24,6 +24,22 @@ obj2html('model.obj', 'index.html') display(HTML('index.html')) ``` +* run into [streamlit](https://streamlit.io/) app ([streamlit_example.py](examples/streamlit_example.py)): +``` +# pip install obj2html streamlit +# have a model.obj (wget https://gitlab.com/nicolalandro/obj2html/-/raw/main/test/assets/model.obj) + +import streamlit as st +import streamlit.components.v1 as components +from obj2html import obj2html + +html_string = obj2html("model.obj", html_elements_only=True) +components.html(html_string) +with open("model.obj") as f: + st.download_button('Download model.obj', f, file_name="download_name.obj") +``` +![](imgs/streamlit_example.png) + ## Features @@ -33,7 +49,7 @@ display(HTML('index.html')) - [x] pypi doc add image - [x] edit html positions and other 3D params - [x] add param for streamlit -- [ ] document param for streamlit +- [x] document param for streamlit - [ ] dist wheel - [ ] load three.js as static file - [ ] .mat files support diff --git a/examples/jupyter_example.ipynb b/examples/jupyter_example.ipynb new file mode 100644 index 0000000..e11c535 --- /dev/null +++ b/examples/jupyter_example.ipynb @@ -0,0 +1,189 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "name": "Demo_obj2html.ipynb", + "provenance": [], + "collapsed_sections": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "code", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yhAY5KFy1gi2", + "outputId": "248d496f-421e-4b92-dc90-8e91cee03c01" + }, + "source": [ + "! pip install obj2html\n", + "! wget https://gitlab.com/nicolalandro/obj2html/-/raw/main/test/assets/model.obj" + ], + "execution_count": null, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting obj2html==0.12\n", + " Downloading obj2html-0.12.tar.gz (3.4 kB)\n", + "Building wheels for collected packages: obj2html\n", + " Building wheel for obj2html (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for obj2html: filename=obj2html-0.12-py3-none-any.whl size=3801 sha256=b5b7db9f171c91da798ee6ddc805451863ecd34f39221935bdb68d7cab6ae352\n", + " Stored in directory: /root/.cache/pip/wheels/8d/2e/a7/c7a4aa0a197f80a9cabb39e4da48905cf09b0f26244afb2841\n", + "Successfully built obj2html\n", + "Installing collected packages: obj2html\n", + " Attempting uninstall: obj2html\n", + " Found existing installation: obj2html 0.11\n", + " Uninstalling obj2html-0.11:\n", + " Successfully uninstalled obj2html-0.11\n", + "Successfully installed obj2html-0.12\n", + "--2021-11-14 16:05:58-- https://gitlab.com/nicolalandro/obj2html/-/raw/main/test/assets/model.obj\n", + "Resolving gitlab.com (gitlab.com)... 172.65.251.78, 2606:4700:90:0:f22e:fbec:5bed:a9b9\n", + "Connecting to gitlab.com (gitlab.com)|172.65.251.78|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 9887179 (9.4M) [text/plain]\n", + "Saving to: ‘model.obj.4’\n", + "\n", + "model.obj.4 100%[===================>] 9.43M --.-KB/s in 0.06s \n", + "\n", + "2021-11-14 16:05:58 (157 MB/s) - ‘model.obj.4’ saved [9887179/9887179]\n", + "\n" + ] + } + ] + }, + { + "cell_type": "code", + "metadata": { + "colab": { + "background_save": true, + "base_uri": "https://localhost:8080/", + "height": 171 + }, + "id": "jeTD6bmh2MX6", + "outputId": "945bcf90-70e3-407b-ad54-79aae1246120" + }, + "source": [ + "from obj2html import obj2html\n", + "from IPython.display import display, HTML\n", + "obj2html('model.obj', 'index.html')\n", + "display(HTML('index.html'))" + ], + "execution_count": null, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ] + } + ] +} \ No newline at end of file diff --git a/examples/stramlit_example.py b/examples/stramlit_example.py new file mode 100644 index 0000000..514bac8 --- /dev/null +++ b/examples/stramlit_example.py @@ -0,0 +1,10 @@ +import streamlit as st +import streamlit.components.v1 as components +from obj2html import obj2html + +# run in the root folder, not inside exaples, to have the relative path working +obj_path = "test/assets/model.obj" +html_string = obj2html(obj_path, html_elements_only=True) +components.html(html_string) +with open(obj_path) as f: + st.download_button('Download model.obj', f, file_name="model.obj") diff --git a/imgs/streamlit_example.png b/imgs/streamlit_example.png new file mode 100644 index 0000000000000000000000000000000000000000..591ef400b62f0a50435cb130c1aadb68156c3ffb GIT binary patch literal 15357 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