├── .gitignore
├── .streamlit
└── config.toml
├── README.md
├── requirements.txt
├── streamlit_app.py
└── streamlit_gallery
├── __init__.py
├── apps
├── __init__.py
└── gallery.py
├── components
├── __init__.py
├── ace_editor
│ ├── __init__.py
│ └── streamlit_app.py
├── discourse
│ ├── __init__.py
│ └── streamlit_app.py
├── disqus
│ ├── __init__.py
│ └── streamlit_app.py
├── elements
│ ├── README.md
│ ├── __init__.py
│ ├── dashboard
│ │ ├── __init__.py
│ │ ├── card.py
│ │ ├── dashboard.py
│ │ ├── datagrid.py
│ │ ├── editor.py
│ │ ├── pie.py
│ │ ├── player.py
│ │ └── radar.py
│ └── streamlit_app.py
├── pandas_profiling
│ ├── __init__.py
│ └── streamlit_app.py
├── quill_editor
│ ├── __init__.py
│ └── streamlit_app.py
└── react_player
│ ├── __init__.py
│ └── streamlit_app.py
└── utils
├── __init__.py
├── page.py
└── readme.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Streamlit
2 | .streamlit/*
3 | !.streamlit/config.toml
4 | !*/frontend/.env
5 |
6 | # Visual Studio Code
7 | .vscode/*
8 | #!.vscode/settings.json
9 | !.vscode/tasks.json
10 | !.vscode/launch.json
11 | !.vscode/extensions.json
12 | *.code-workspace
13 |
14 | # Local History for Visual Studio Code
15 | .history/
16 |
17 | # Byte-compiled / optimized / DLL files
18 | __pycache__/
19 | *.py[cod]
20 | *$py.class
21 |
22 | # C extensions
23 | *.so
24 |
25 | # Distribution / packaging
26 | .Python
27 | build/
28 | develop-eggs/
29 | dist/
30 | downloads/
31 | eggs/
32 | .eggs/
33 | lib/
34 | lib64/
35 | parts/
36 | sdist/
37 | var/
38 | wheels/
39 | share/python-wheels/
40 | *.egg-info/
41 | .installed.cfg
42 | *.egg
43 | MANIFEST
44 |
45 | # PyInstaller
46 | # Usually these files are written by a python script from a template
47 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
48 | *.manifest
49 | *.spec
50 |
51 | # Installer logs
52 | pip-log.txt
53 | pip-delete-this-directory.txt
54 |
55 | # Unit test / coverage reports
56 | htmlcov/
57 | .tox/
58 | .nox/
59 | .coverage
60 | .coverage.*
61 | .cache
62 | nosetests.xml
63 | coverage.xml
64 | *.cover
65 | *.py,cover
66 | .hypothesis/
67 | .pytest_cache/
68 | cover/
69 |
70 | # Translations
71 | *.mo
72 | *.pot
73 |
74 | # Django stuff:
75 | *.log
76 | local_settings.py
77 | db.sqlite3
78 | db.sqlite3-journal
79 |
80 | # Flask stuff:
81 | instance/
82 | .webassets-cache
83 |
84 | # Scrapy stuff:
85 | .scrapy
86 |
87 | # Sphinx documentation
88 | docs/_build/
89 |
90 | # PyBuilder
91 | .pybuilder/
92 | target/
93 |
94 | # Jupyter Notebook
95 | .ipynb_checkpoints
96 |
97 | # IPython
98 | profile_default/
99 | ipython_config.py
100 |
101 | # pyenv
102 | # For a library or package, you might want to ignore these files since the code is
103 | # intended to run in multiple environments; otherwise, check them in:
104 | .python-version
105 |
106 | # pipenv
107 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
108 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
109 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
110 | # install all needed dependencies.
111 | #Pipfile.lock
112 |
113 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
114 | __pypackages__/
115 |
116 | # Celery stuff
117 | celerybeat-schedule
118 | celerybeat.pid
119 |
120 | # SageMath parsed files
121 | *.sage.py
122 |
123 | # Environments
124 | .env
125 | .venv
126 | env/
127 | venv/
128 | ENV/
129 | env.bak/
130 | venv.bak/
131 |
132 | # Spyder project settings
133 | .spyderproject
134 | .spyproject
135 |
136 | # Rope project settings
137 | .ropeproject
138 |
139 | # mkdocs documentation
140 | /site
141 |
142 | # mypy
143 | .mypy_cache/
144 | .dmypy.json
145 | dmypy.json
146 |
147 | # Pyre type checker
148 | .pyre/
149 |
150 | # pytype static type analyzer
151 | .pytype/
152 |
153 | # Cython debug symbols
154 | cython_debug/
155 |
156 | # Logs
157 | logs
158 | *.log
159 | npm-debug.log*
160 | yarn-debug.log*
161 | yarn-error.log*
162 | lerna-debug.log*
163 |
164 | # Diagnostic reports (https://nodejs.org/api/report.html)
165 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
166 |
167 | # Runtime data
168 | pids
169 | *.pid
170 | *.seed
171 | *.pid.lock
172 |
173 | # Directory for instrumented libs generated by jscoverage/JSCover
174 | lib-cov
175 |
176 | # Coverage directory used by tools like istanbul
177 | coverage
178 | *.lcov
179 |
180 | # nyc test coverage
181 | .nyc_output
182 |
183 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
184 | .grunt
185 |
186 | # Bower dependency directory (https://bower.io/)
187 | bower_components
188 |
189 | # node-waf configuration
190 | .lock-wscript
191 |
192 | # Compiled binary addons (https://nodejs.org/api/addons.html)
193 | build/Release
194 |
195 | # Dependency directories
196 | node_modules/
197 | jspm_packages/
198 |
199 | # Snowpack dependency directory (https://snowpack.dev/)
200 | web_modules/
201 |
202 | # TypeScript cache
203 | *.tsbuildinfo
204 |
205 | # Optional npm cache directory
206 | .npm
207 |
208 | # Optional eslint cache
209 | .eslintcache
210 |
211 | # Microbundle cache
212 | .rpt2_cache/
213 | .rts2_cache_cjs/
214 | .rts2_cache_es/
215 | .rts2_cache_umd/
216 |
217 | # Optional REPL history
218 | .node_repl_history
219 |
220 | # Output of 'npm pack'
221 | *.tgz
222 |
223 | # Yarn Integrity file
224 | .yarn-integrity
225 |
226 | # dotenv environment variables file
227 | .env
228 | .env.test
229 |
230 | # parcel-bundler cache (https://parceljs.org/)
231 | .cache
232 | .parcel-cache
233 |
234 | # Next.js build output
235 | .next
236 | out
237 |
238 | # Nuxt.js build / generate output
239 | .nuxt
240 | dist
241 |
242 | # Gatsby files
243 | .cache/
244 | # Comment in the public line in if your project uses Gatsby and not Next.js
245 | # https://nextjs.org/blog/next-9-1#public-directory-support
246 | # public
247 |
248 | # vuepress build output
249 | .vuepress/dist
250 |
251 | # Serverless directories
252 | .serverless/
253 |
254 | # FuseBox cache
255 | .fusebox/
256 |
257 | # DynamoDB Local files
258 | .dynamodb/
259 |
260 | # TernJS port file
261 | .tern-port
262 |
263 | # Stores VSCode versions used for testing VSCode extensions
264 | .vscode-test
265 |
266 | # yarn v2
267 | .yarn/cache
268 | .yarn/unplugged
269 | .yarn/build-state.yml
270 | .yarn/install-state.gz
271 | .pnp.*
272 |
--------------------------------------------------------------------------------
/.streamlit/config.toml:
--------------------------------------------------------------------------------
1 | [theme]
2 | base="dark"
3 | backgroundColor="#1e1e1e"
4 | secondaryBackgroundColor="#252526"
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🎉 Streamlit Gallery
2 |
3 | [![Open in Streamlit][share_badge]][share_link] [![GitHub][github_badge]][github_link]
4 |
5 | [share_badge]: https://static.streamlit.io/badges/streamlit_badge_black_white.svg
6 | [share_link]: https://share.streamlit.io/okld/streamlit-gallery/main
7 |
8 | [github_badge]: https://badgen.net/badge/icon/GitHub?icon=github&color=black&label
9 | [github_link]: https://github.com/okld/streamlit-gallery
10 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # Core
2 | streamlit
3 |
4 | # Streamlit components
5 | streamlit-ace
6 | streamlit-discourse
7 | streamlit-disqus
8 | streamlit-elements
9 | streamlit-pandas-profiling
10 | streamlit-player
11 | streamlit-quill
12 |
13 | # Dependencies
14 | pandas-profiling
15 | requests
16 |
--------------------------------------------------------------------------------
/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from streamlit_gallery import apps, components
4 | from streamlit_gallery.utils.page import page_group
5 |
6 | def main():
7 | page = page_group("p")
8 |
9 | with st.sidebar:
10 | st.title("🎈 Okld's Gallery")
11 |
12 | with st.expander("✨ APPS", True):
13 | page.item("Streamlit gallery", apps.gallery, default=True)
14 |
15 | with st.expander("🧩 COMPONENTS", True):
16 | page.item("Ace editor", components.ace_editor)
17 | page.item("Disqus", components.disqus)
18 | page.item("Elements⭐", components.elements)
19 | page.item("Pandas profiling", components.pandas_profiling)
20 | page.item("Quill editor", components.quill_editor)
21 | page.item("React player", components.react_player)
22 |
23 | page.show()
24 |
25 | if __name__ == "__main__":
26 | st.set_page_config(page_title="Streamlit Gallery by Okld", page_icon="🎈", layout="wide")
27 | main()
28 |
--------------------------------------------------------------------------------
/streamlit_gallery/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/apps/__init__.py:
--------------------------------------------------------------------------------
1 | from .gallery import main as gallery
2 |
--------------------------------------------------------------------------------
/streamlit_gallery/apps/gallery.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from pathlib import Path
4 |
5 |
6 | def main():
7 | st.markdown((Path(__file__).parents[2]/"README.md").read_text())
8 |
9 |
10 | if __name__ == "__main__":
11 | main()
12 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/__init__.py:
--------------------------------------------------------------------------------
1 | from .ace_editor.streamlit_app import main as ace_editor
2 | from .discourse.streamlit_app import main as discourse
3 | from .disqus.streamlit_app import main as disqus
4 | from .elements.streamlit_app import main as elements
5 | from .pandas_profiling.streamlit_app import main as pandas_profiling
6 | from .quill_editor.streamlit_app import main as quill_editor
7 | from .react_player.streamlit_app import main as react_player
8 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/ace_editor/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/ace_editor/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/ace_editor/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from streamlit_ace import st_ace, KEYBINDINGS, LANGUAGES, THEMES
4 | from streamlit_gallery.utils.readme import readme
5 |
6 |
7 | def main():
8 | with readme("streamlit-ace", st_ace, __file__):
9 | c1, c2 = st.columns([3, 1])
10 |
11 | c2.subheader("Parameters")
12 |
13 | with c1:
14 | content = st_ace(
15 | placeholder=c2.text_input("Editor placeholder", value="Write your code here"),
16 | language=c2.selectbox("Language mode", options=LANGUAGES, index=121),
17 | theme=c2.selectbox("Theme", options=THEMES, index=35),
18 | keybinding=c2.selectbox("Keybinding mode", options=KEYBINDINGS, index=3),
19 | font_size=c2.slider("Font size", 5, 24, 14),
20 | tab_size=c2.slider("Tab size", 1, 8, 4),
21 | show_gutter=c2.checkbox("Show gutter", value=True),
22 | show_print_margin=c2.checkbox("Show print margin", value=False),
23 | wrap=c2.checkbox("Wrap enabled", value=False),
24 | auto_update=c2.checkbox("Auto update", value=False),
25 | readonly=c2.checkbox("Read-only", value=False),
26 | min_lines=45,
27 | key="ace",
28 | )
29 |
30 | if content:
31 | st.subheader("Content")
32 | st.text(content)
33 |
34 |
35 | if __name__ == "__main__":
36 | main()
37 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/discourse/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/discourse/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/discourse/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from streamlit_discourse import st_discourse
4 | from streamlit_gallery.utils.readme import readme
5 |
6 |
7 | def main():
8 | with readme("streamlit-discourse", st_discourse, __file__):
9 | st_discourse("discuss.streamlit.io", 8061, key="discourse")
10 |
11 |
12 | if __name__ == "__main__":
13 | main()
14 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/disqus/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/disqus/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/disqus/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from streamlit_disqus import st_disqus
4 | from streamlit_gallery.utils.readme import readme
5 |
6 |
7 | def main():
8 | with readme("streamlit-disqus", st_disqus, __file__):
9 | st_disqus("streamlit-disqus-demo")
10 |
11 |
12 | if __name__ == "__main__":
13 | main()
14 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/README.md:
--------------------------------------------------------------------------------
1 | ### 1. Introduction
2 |
3 | Streamlit Elements is a component that gives you the tools to compose beautiful applications with Material UI widgets, Monaco, Nivo charts, and more.
4 | It also includes a feature to create draggable and resizable dashboards.
5 |
6 | #### Installation
7 |
8 | ```sh
9 | pip install streamlit-elements==0.1.*
10 | ```
11 |
12 | **Caution**: It is recommended to pin the version to `0.1.*`. Future versions might introduce breaking API changes.
13 |
14 | #### Available elements and objects
15 |
16 | Here is a list of elements and objects you can import in your app:
17 |
18 | Element | Description
19 | :--------:|:-----------
20 | elements | Create a frame where elements will be displayed.
21 | dashboard | Build a draggable and resizable dashboard.
22 | mui | Material UI (MUI) widgets and icons.
23 | html | HTML objects.
24 | editor | Monaco code and diff editor that powers Visual Studio Code.
25 | nivo | Nivo chart library.
26 | media | Media player.
27 | sync | Callback to synchronize Streamlit's session state with elements events data.
28 | lazy | Defer a callback call until another non-lazy callback is called.
29 |
30 | #### Caution
31 |
32 | - A few Material UI widgets may not work as expected (ie. modal dialogs and snackbars).
33 | - Using many element frames can significantly impact your app's performance. Try to gather elements in few frames at most.
34 |
35 | ---
36 |
37 | ### 2. Display elements
38 |
39 | #### 2.1. Create an element with a child
40 |
41 | ```python
42 | # First, import the elements you need
43 |
44 | from streamlit_elements import elements, mui, html
45 |
46 | # Create a frame where Elements widgets will be displayed.
47 | #
48 | # Elements widgets will not render outside of this frame.
49 | # Native Streamlit widgets will not render inside this frame.
50 | #
51 | # elements() takes a key as parameter.
52 | # This key can't be reused by another frame or Streamlit widget.
53 |
54 | with elements("new_element"):
55 |
56 | # Let's create a Typography element with "Hello world" as children.
57 | # The first step is to check Typography's documentation on MUI:
58 | # https://mui.com/components/typography/
59 | #
60 | # Here is how you would write it in React JSX:
61 | #
62 | #
63 | # Hello world
64 | #
65 |
66 | mui.Typography("Hello world")
67 | ```
68 | - MUI Typography: https://mui.com/components/typography/
69 |
70 | ---
71 |
72 | #### 2.2. Create an element with multiple children
73 |
74 | ```python
75 | with elements("multiple_children"):
76 |
77 | # You have access to Material UI icons using: mui.icon.IconNameHere
78 | #
79 | # Multiple children can be added in a single element.
80 | #
81 | #
86 |
87 | mui.Button(
88 | mui.icon.EmojiPeople,
89 | mui.icon.DoubleArrow,
90 | "Button with multiple children"
91 | )
92 |
93 | # You can also add children to an element using a 'with' statement.
94 | #
95 | #
102 |
103 | with mui.Button:
104 | mui.icon.EmojiPeople()
105 | mui.icon.DoubleArrow()
106 | mui.Typography("Button with multiple children")
107 | ```
108 | - MUI button: https://mui.com/components/buttons/
109 | - MUI icons: https://mui.com/components/material-icons/
110 |
111 | ---
112 |
113 | #### 2.3. Create an element with nested children
114 |
115 | ```python
116 | with elements("nested_children"):
117 |
118 | # You can nest children using multiple 'with' statements.
119 | #
120 | #
121 | #
122 | # Hello world
123 | # Goodbye world
124 | #
125 | #
126 |
127 | with mui.Paper:
128 | with mui.Typography:
129 | html.p("Hello world")
130 | html.p("Goodbye world")
131 | ```
132 | - MUI paper: https://mui.com/components/paper/
133 |
134 | ---
135 |
136 | #### 2.4. Add properties to an element
137 |
138 | ```python
139 | with elements("properties"):
140 |
141 | # You can add properties to elements with named parameters.
142 | #
143 | # To find all available parameters for a given element, you can
144 | # refer to its related documentation on mui.com for MUI widgets,
145 | # on https://microsoft.github.io/monaco-editor/ for Monaco editor,
146 | # and so on.
147 | #
148 | #
149 | #
150 | #
151 |
152 | with mui.Paper(elevation=3, variant="outlined", square=True):
153 | mui.TextField(
154 | label="My text input",
155 | defaultValue="Type here",
156 | variant="outlined",
157 | )
158 |
159 | # If you must pass a parameter which is also a Python keyword, you can append an
160 | # underscore to avoid a syntax error.
161 | #
162 | #
163 |
164 | mui.Collapse(in_=True)
165 |
166 | # mui.collapse(in=True)
167 | # > Syntax error: 'in' is a Python keyword:
168 | ```
169 | - MUI text field: https://mui.com/components/text-fields/
170 |
171 | ---
172 |
173 | #### 2.5. Apply custom CSS styles
174 |
175 | ##### 2.5.1. Material UI elements
176 |
177 | ```python
178 | with elements("style_mui_sx"):
179 |
180 | # For Material UI elements, use the 'sx' property.
181 | #
182 | #
191 | # Some text in a styled box
192 | #
193 |
194 | mui.Box(
195 | "Some text in a styled box",
196 | sx={
197 | "bgcolor": "background.paper",
198 | "boxShadow": 1,
199 | "borderRadius": 2,
200 | "p": 2,
201 | "minWidth": 300,
202 | }
203 | )
204 | ```
205 | - MUI's **sx** property: https://mui.com/system/the-sx-prop/
206 |
207 | ##### 2.5.2. Other elements
208 |
209 | ```python
210 | with elements("style_elements_css"):
211 |
212 | # For any other element, use the 'css' property.
213 | #
214 | #
222 | # This has a hotpink background
223 | #
224 |
225 | html.div(
226 | "This has a hotpink background",
227 | css={
228 | "backgroundColor": "hotpink",
229 | "&:hover": {
230 | "color": "lightgreen"
231 | }
232 | }
233 | )
234 | ```
235 | - Emotion's **css** property: https://emotion.sh/docs/css-prop#object-styles
236 |
237 | ---
238 |
239 | ### 3. Callbacks
240 |
241 | #### 3.1. Retrieve an element's data
242 |
243 | ```python
244 | import streamlit as st
245 |
246 | with elements("callbacks_retrieve_data"):
247 |
248 | # Some element allows executing a callback on specific event.
249 | #
250 | # const [name, setName] = React.useState("")
251 | # const handleChange = (event) => {
252 | # // You can see here that a text field value
253 | # // is stored in event.target.value
254 | # setName(event.target.value)
255 | # }
256 | #
257 | #
261 |
262 | # Initialize a new item in session state called "my_text"
263 | if "my_text" not in st.session_state:
264 | st.session_state.my_text = ""
265 |
266 | # When text field changes, this function will be called.
267 | # To know which parameters are passed to the callback,
268 | # you can refer to the element's documentation.
269 | def handle_change(event):
270 | st.session_state.my_text = event.target.value
271 |
272 | # Here we display what we have typed in our text field
273 | mui.Typography(st.session_state.my_text)
274 |
275 | # And here we give our 'handle_change' callback to the 'onChange'
276 | # property of the text field.
277 | mui.TextField(label="Input some text here", onChange=handle_change)
278 | ```
279 | - MUI text field event: https://mui.com/components/text-fields/#uncontrolled-vs-controlled
280 | - MUI text field API: https://mui.com/api/text-field/
281 |
282 | ---
283 |
284 | #### 3.2. Synchronize a session state item with an element event using sync()
285 |
286 | ```python
287 | with elements("callbacks_sync"):
288 |
289 | # If you just want to store callback parameters into Streamlit's session state
290 | # like above, you can also use the special function sync().
291 | #
292 | # When an onChange event occurs, the callback is called with an event data object
293 | # as argument. In the example below, we are synchronizing that event data object with
294 | # the session state item 'my_event'.
295 | #
296 | # If an event passes more than one parameter, you can synchronize as many session state item
297 | # as needed like so:
298 | # >>> sync("my_first_param", "my_second_param")
299 | #
300 | # If you want to ignore the first parameter of an event but keep synchronizing the second,
301 | # pass None to sync:
302 | # >>> sync(None, "second_parameter_to_keep")
303 |
304 | from streamlit_elements import sync
305 |
306 | if "my_event" not in st.session_state:
307 | st.session_state.my_event = None
308 |
309 | if st.session_state.my_event is not None:
310 | text = st.session_state.my_event.target.value
311 | else:
312 | text = ""
313 |
314 | mui.Typography(text)
315 | mui.TextField(label="Input some text here", onChange=sync("my_event"))
316 | ```
317 |
318 | ---
319 |
320 | #### 3.3. Avoid too many reloads with lazy()
321 |
322 | ```python
323 | with elements("callbacks_lazy"):
324 |
325 | # With the two first examples, each time you input a letter into the text field,
326 | # the callback is invoked but the whole app is reloaded as well.
327 | #
328 | # To avoid reloading the whole app on every input, you can wrap your callback with
329 | # lazy(). This will defer the callback invocation until another non-lazy callback
330 | # is invoked. This can be useful to implement forms.
331 |
332 | from streamlit_elements import lazy
333 |
334 | if "first_name" not in st.session_state:
335 | st.session_state.first_name = None
336 | st.session_state.last_name = None
337 |
338 | if st.session_state.first_name is not None:
339 | first_name = st.session_state.first_name.target.value
340 | else:
341 | first_name = "John"
342 |
343 | if st.session_state.last_name is not None:
344 | last_name = st.session_state.last_name.target.value
345 | else:
346 | last_name = "Doe"
347 |
348 | def set_last_name(event):
349 | st.session_state.last_name = event
350 |
351 | # Display first name and last name
352 | mui.Typography("Your first name: ", first_name)
353 | mui.Typography("Your last name: ", last_name)
354 |
355 | # Lazily synchronize onChange with first_name and last_name state.
356 | # Inputting some text won't synchronize the value yet.
357 | mui.TextField(label="First name", onChange=lazy(sync("first_name")))
358 |
359 | # You can also pass regular python functions to lazy().
360 | mui.TextField(label="Last name", onChange=lazy(set_last_name))
361 |
362 | # Here we give a non-lazy callback to onClick using sync().
363 | # We are not interested in getting onClick event data object,
364 | # so we call sync() with no argument.
365 | #
366 | # You can use either sync() or a regular python function.
367 | # As long as the callback is not wrapped with lazy(), its invocation will
368 | # also trigger every other defered callbacks.
369 | mui.Button("Update first namd and last name", onClick=sync())
370 | ```
371 |
372 | ---
373 |
374 | #### 3.4. Invoke a callback when a sequence is pressed using event.Hotkey()
375 |
376 | ```python
377 | with elements("callbacks_hotkey"):
378 |
379 | # Invoke a callback when a specific hotkey sequence is pressed.
380 | #
381 | # For more information regarding sequences syntax and supported keys,
382 | # go to Mousetrap's project page linked below.
383 | #
384 | # /!\ Hotkeys work if you don't have focus on Streamlit Elements's frame /!\
385 | # /!\ As with other callbacks, this reruns the whole app /!\
386 |
387 | from streamlit_elements import event
388 |
389 | def hotkey_pressed():
390 | print("Hotkey pressed")
391 |
392 | event.Hotkey("g", hotkey_pressed)
393 |
394 | # If you want your hotkey to work even in text fields, set bind_inputs to True.
395 | event.Hotkey("h", hotkey_pressed, bindInputs=True)
396 | mui.TextField(label="Try pressing 'h' while typing some text here.")
397 |
398 | # If you want to override default hotkeys (ie. ctrl+f to search in page),
399 | # set overrideDefault to True.
400 | event.Hotkey("ctrl+f", hotkey_pressed, overrideDefault=True)
401 | ```
402 | - Mousetrap: https://craig.is/killing/mice
403 | - Github page: https://github.com/ccampbell/mousetrap
404 |
405 | ---
406 |
407 | #### 3.5. Invoke a callback periodically using event.Interval()
408 |
409 | ```python
410 | with elements("callbacks_interval"):
411 |
412 | # Invoke a callback every n seconds.
413 | #
414 | # /!\ As with other callbacks, this reruns the whole app /!\
415 |
416 | def call_every_second():
417 | print("Hello world")
418 |
419 | event.Interval(1, call_every_second)
420 | ```
421 |
422 | ---
423 |
424 | ### 4. Draggable and resizable dashboard
425 |
426 | ```python
427 | with elements("dashboard"):
428 |
429 | # You can create a draggable and resizable dashboard using
430 | # any element available in Streamlit Elements.
431 |
432 | from streamlit_elements import dashboard
433 |
434 | # First, build a default layout for every element you want to include in your dashboard
435 |
436 | layout = [
437 | # Parameters: element_identifier, x_pos, y_pos, width, height, [item properties...]
438 | dashboard.Item("first_item", 0, 0, 2, 2),
439 | dashboard.Item("second_item", 2, 0, 2, 2, isDraggable=False, moved=False),
440 | dashboard.Item("third_item", 0, 2, 1, 1, isResizable=False),
441 | ]
442 |
443 | # Next, create a dashboard layout using the 'with' syntax. It takes the layout
444 | # as first parameter, plus additional properties you can find in the GitHub links below.
445 |
446 | with dashboard.Grid(layout):
447 | mui.Paper("First item", key="first_item")
448 | mui.Paper("Second item (cannot drag)", key="second_item")
449 | mui.Paper("Third item (cannot resize)", key="third_item")
450 |
451 | # If you want to retrieve updated layout values as the user move or resize dashboard items,
452 | # you can pass a callback to the onLayoutChange event parameter.
453 |
454 | def handle_layout_change(updated_layout):
455 | # You can save the layout in a file, or do anything you want with it.
456 | # You can pass it back to dashboard.Grid() if you want to restore a saved layout.
457 | print(updated_layout)
458 |
459 | with dashboard.Grid(layout, onLayoutChange=handle_layout_change):
460 | mui.Paper("First item", key="first_item")
461 | mui.Paper("Second item (cannot drag)", key="second_item")
462 | mui.Paper("Third item (cannot resize)", key="third_item")
463 | ```
464 | - Dashboard item properties: https://github.com/react-grid-layout/react-grid-layout#grid-item-props
465 | - Dashboard grid properties (Streamlit Elements uses the Responsive grid layout):
466 | - https://github.com/react-grid-layout/react-grid-layout#grid-layout-props
467 | - https://github.com/react-grid-layout/react-grid-layout#responsive-grid-layout-props
468 |
469 | ---
470 |
471 | ### 5. Other third-party elements
472 |
473 | #### 5.1. Monaco code and diff editor
474 |
475 | ```python
476 | with elements("monaco_editors"):
477 |
478 | # Streamlit Elements embeds Monaco code and diff editor that powers Visual Studio Code.
479 | # You can configure editor's behavior and features with the 'options' parameter.
480 | #
481 | # Streamlit Elements uses an unofficial React implementation (GitHub links below for
482 | # documentation).
483 |
484 | from streamlit_elements import editor
485 |
486 | if "content" not in st.session_state:
487 | st.session_state.content = "Default value"
488 |
489 | mui.Typography("Content: ", st.session_state.content)
490 |
491 | def update_content(value):
492 | st.session_state.content = value
493 |
494 | editor.Monaco(
495 | height=300,
496 | defaultValue=st.session_state.content,
497 | onChange=lazy(update_content)
498 | )
499 |
500 | mui.Button("Update content", onClick=sync())
501 |
502 | editor.MonacoDiff(
503 | original="Happy Streamlit-ing!",
504 | modified="Happy Streamlit-in' with Elements!",
505 | height=300,
506 | )
507 | ```
508 | - Monaco examples and properties: https://github.com/suren-atoyan/monaco-react
509 | - Code editor options: https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html
510 | - Diff editor options: https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneDiffEditorConstructionOptions.html
511 | - Monaco project page: https://microsoft.github.io/monaco-editor/
512 |
513 | ---
514 |
515 | #### 5.2. Nivo charts
516 |
517 | ```python
518 | with elements("nivo_charts"):
519 |
520 | # Streamlit Elements includes 45 dataviz components powered by Nivo.
521 |
522 | from streamlit_elements import nivo
523 |
524 | DATA = [
525 | { "taste": "fruity", "chardonay": 93, "carmenere": 61, "syrah": 114 },
526 | { "taste": "bitter", "chardonay": 91, "carmenere": 37, "syrah": 72 },
527 | { "taste": "heavy", "chardonay": 56, "carmenere": 95, "syrah": 99 },
528 | { "taste": "strong", "chardonay": 64, "carmenere": 90, "syrah": 30 },
529 | { "taste": "sunny", "chardonay": 119, "carmenere": 94, "syrah": 103 },
530 | ]
531 |
532 | with mui.Box(sx={"height": 500}):
533 | nivo.Radar(
534 | data=DATA,
535 | keys=[ "chardonay", "carmenere", "syrah" ],
536 | indexBy="taste",
537 | valueFormat=">-.2f",
538 | margin={ "top": 70, "right": 80, "bottom": 40, "left": 80 },
539 | borderColor={ "from": "color" },
540 | gridLabelOffset=36,
541 | dotSize=10,
542 | dotColor={ "theme": "background" },
543 | dotBorderWidth=2,
544 | motionConfig="wobbly",
545 | legends=[
546 | {
547 | "anchor": "top-left",
548 | "direction": "column",
549 | "translateX": -50,
550 | "translateY": -40,
551 | "itemWidth": 80,
552 | "itemHeight": 20,
553 | "itemTextColor": "#999",
554 | "symbolSize": 12,
555 | "symbolShape": "circle",
556 | "effects": [
557 | {
558 | "on": "hover",
559 | "style": {
560 | "itemTextColor": "#000"
561 | }
562 | }
563 | ]
564 | }
565 | ],
566 | theme={
567 | "background": "#FFFFFF",
568 | "textColor": "#31333F",
569 | "tooltip": {
570 | "container": {
571 | "background": "#FFFFFF",
572 | "color": "#31333F",
573 | }
574 | }
575 | }
576 | )
577 | ```
578 | - Nivo charts: https://nivo.rocks/
579 | - Github page: https://github.com/plouc/nivo
580 |
581 | ---
582 |
583 | #### 5.3. Media player
584 |
585 | ```python
586 | with elements("media_player"):
587 |
588 | # Play video from many third-party sources: YouTube, Facebook, Twitch,
589 | # SoundCloud, Streamable, Vimeo, Wistia, Mixcloud, DailyMotion and Kaltura.
590 | #
591 | # This element is powered by ReactPlayer (GitHub link below).
592 |
593 | from streamlit_elements import media
594 |
595 | media.Player(url="https://www.youtube.com/watch?v=iik25wqIuFo", controls=True)
596 | ```
597 | - ReactPlayer properties: https://github.com/cookpete/react-player#props
598 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/elements/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/__init__.py:
--------------------------------------------------------------------------------
1 | from .card import Card
2 | from .dashboard import Dashboard
3 | from .datagrid import DataGrid
4 | from .editor import Editor
5 | from .pie import Pie
6 | from .player import Player
7 | from .radar import Radar
8 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/card.py:
--------------------------------------------------------------------------------
1 | from streamlit_elements import mui
2 | from .dashboard import Dashboard
3 |
4 |
5 | class Card(Dashboard.Item):
6 |
7 | DEFAULT_CONTENT = (
8 | "This impressive paella is a perfect party dish and a fun meal to cook "
9 | "together with your guests. Add 1 cup of frozen peas along with the mussels, "
10 | "if you like."
11 | )
12 |
13 | def __call__(self, content):
14 | with mui.Card(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
15 | mui.CardHeader(
16 | title="Shrimp and Chorizo Paella",
17 | subheader="September 14, 2016",
18 | avatar=mui.Avatar("R", sx={"bgcolor": "red"}),
19 | action=mui.IconButton(mui.icon.MoreVert),
20 | className=self._draggable_class,
21 | )
22 | mui.CardMedia(
23 | component="img",
24 | height=194,
25 | image="https://mui.com/static/images/cards/paella.jpg",
26 | alt="Paella dish",
27 | )
28 |
29 | with mui.CardContent(sx={"flex": 1}):
30 | mui.Typography(content)
31 |
32 | with mui.CardActions(disableSpacing=True):
33 | mui.IconButton(mui.icon.Favorite)
34 | mui.IconButton(mui.icon.Share)
35 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/dashboard.py:
--------------------------------------------------------------------------------
1 | from uuid import uuid4
2 | from abc import ABC, abstractmethod
3 | from streamlit_elements import dashboard, mui
4 | from contextlib import contextmanager
5 |
6 |
7 | class Dashboard:
8 |
9 | DRAGGABLE_CLASS = "draggable"
10 |
11 | def __init__(self):
12 | self._layout = []
13 |
14 | def _register(self, item):
15 | self._layout.append(item)
16 |
17 | @contextmanager
18 | def __call__(self, **props):
19 | # Draggable classname query selector.
20 | props["draggableHandle"] = f".{Dashboard.DRAGGABLE_CLASS}"
21 |
22 | with dashboard.Grid(self._layout, **props):
23 | yield
24 |
25 | class Item(ABC):
26 |
27 | def __init__(self, board, x, y, w, h, **item_props):
28 | self._key = str(uuid4())
29 | self._draggable_class = Dashboard.DRAGGABLE_CLASS
30 | self._dark_mode = True
31 | board._register(dashboard.Item(self._key, x, y, w, h, **item_props))
32 |
33 | def _switch_theme(self):
34 | self._dark_mode = not self._dark_mode
35 |
36 | @contextmanager
37 | def title_bar(self, padding="5px 15px 5px 15px", dark_switcher=True):
38 | with mui.Stack(
39 | className=self._draggable_class,
40 | alignItems="center",
41 | direction="row",
42 | spacing=1,
43 | sx={
44 | "padding": padding,
45 | "borderBottom": 1,
46 | "borderColor": "divider",
47 | },
48 | ):
49 | yield
50 |
51 | if dark_switcher:
52 | if self._dark_mode:
53 | mui.IconButton(mui.icon.DarkMode, onClick=self._switch_theme)
54 | else:
55 | mui.IconButton(mui.icon.LightMode, sx={"color": "#ffc107"}, onClick=self._switch_theme)
56 |
57 | @abstractmethod
58 | def __call__(self):
59 | """Show elements."""
60 | raise NotImplementedError
61 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/datagrid.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from streamlit_elements import mui
4 | from .dashboard import Dashboard
5 |
6 |
7 | class DataGrid(Dashboard.Item):
8 |
9 | DEFAULT_COLUMNS = [
10 | { "field": 'id', "headerName": 'ID', "width": 90 },
11 | { "field": 'firstName', "headerName": 'First name', "width": 150, "editable": True, },
12 | { "field": 'lastName', "headerName": 'Last name', "width": 150, "editable": True, },
13 | { "field": 'age', "headerName": 'Age', "type": 'number', "width": 110, "editable": True, },
14 | ]
15 | DEFAULT_ROWS = [
16 | { "id": 1, "lastName": 'Snow', "firstName": 'Jon', "age": 35 },
17 | { "id": 2, "lastName": 'Lannister', "firstName": 'Cersei', "age": 42 },
18 | { "id": 3, "lastName": 'Lannister', "firstName": 'Jaime', "age": 45 },
19 | { "id": 4, "lastName": 'Stark', "firstName": 'Arya', "age": 16 },
20 | { "id": 5, "lastName": 'Targaryen', "firstName": 'Daenerys', "age": None },
21 | { "id": 6, "lastName": 'Melisandre', "firstName": None, "age": 150 },
22 | { "id": 7, "lastName": 'Clifford', "firstName": 'Ferrara', "age": 44 },
23 | { "id": 8, "lastName": 'Frances', "firstName": 'Rossini', "age": 36 },
24 | { "id": 9, "lastName": 'Roxie', "firstName": 'Harvey', "age": 65 },
25 | ]
26 |
27 | def _handle_edit(self, params):
28 | print(params)
29 |
30 | def __call__(self, json_data):
31 | try:
32 | data = json.loads(json_data)
33 | except json.JSONDecodeError:
34 | data = self.DEFAULT_ROWS
35 |
36 | with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
37 | with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
38 | mui.icon.ViewCompact()
39 | mui.Typography("Data grid")
40 |
41 | with mui.Box(sx={"flex": 1, "minHeight": 0}):
42 | mui.DataGrid(
43 | columns=self.DEFAULT_COLUMNS,
44 | rows=data,
45 | pageSize=5,
46 | rowsPerPageOptions=[5],
47 | checkboxSelection=True,
48 | disableSelectionOnClick=True,
49 | onCellEditCommit=self._handle_edit,
50 | )
51 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/editor.py:
--------------------------------------------------------------------------------
1 | from functools import partial
2 | from streamlit_elements import mui, editor, sync, lazy
3 | from .dashboard import Dashboard
4 |
5 |
6 | class Editor(Dashboard.Item):
7 |
8 | def __init__(self, *args, **kwargs):
9 | super().__init__(*args, **kwargs)
10 |
11 | self._dark_theme = False
12 | self._index = 0
13 | self._tabs = {}
14 | self._editor_box_style = {
15 | "flex": 1,
16 | "minHeight": 0,
17 | "borderBottom": 1,
18 | "borderTop": 1,
19 | "borderColor": "divider"
20 | }
21 |
22 | def _change_tab(self, _, index):
23 | self._index = index
24 |
25 | def update_content(self, label, content):
26 | self._tabs[label]["content"] = content
27 |
28 | def add_tab(self, label, default_content, language):
29 | self._tabs[label] = {
30 | "content": default_content,
31 | "language": language
32 | }
33 |
34 | def get_content(self, label):
35 | return self._tabs[label]["content"]
36 |
37 | def __call__(self):
38 | with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
39 |
40 | with self.title_bar("0px 15px 0px 15px"):
41 | mui.icon.Terminal()
42 | mui.Typography("Editor")
43 |
44 | with mui.Tabs(value=self._index, onChange=self._change_tab, scrollButtons=True, variant="scrollable", sx={"flex": 1}):
45 | for label in self._tabs.keys():
46 | mui.Tab(label=label)
47 |
48 | for index, (label, tab) in enumerate(self._tabs.items()):
49 | with mui.Box(sx=self._editor_box_style, hidden=(index != self._index)):
50 | editor.Monaco(
51 | css={"padding": "0 2px 0 2px"},
52 | defaultValue=tab["content"],
53 | language=tab["language"],
54 | onChange=lazy(partial(self.update_content, label)),
55 | theme="vs-dark" if self._dark_mode else "light",
56 | path=label,
57 | options={
58 | "wordWrap": True
59 | }
60 | )
61 |
62 | with mui.Stack(direction="row", spacing=2, alignItems="center", sx={"padding": "10px"}):
63 | mui.Button("Apply", variant="contained", onClick=sync())
64 | mui.Typography("Or press ctrl+s", sx={"flex": 1})
65 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/pie.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from streamlit_elements import nivo, mui
4 | from .dashboard import Dashboard
5 |
6 |
7 | class Pie(Dashboard.Item):
8 |
9 | DEFAULT_DATA = [
10 | { "id": "java", "label": "java", "value": 465, "color": "hsl(128, 70%, 50%)" },
11 | { "id": "rust", "label": "rust", "value": 140, "color": "hsl(178, 70%, 50%)" },
12 | { "id": "scala", "label": "scala", "value": 40, "color": "hsl(322, 70%, 50%)" },
13 | { "id": "ruby", "label": "ruby", "value": 439, "color": "hsl(117, 70%, 50%)" },
14 | { "id": "elixir", "label": "elixir", "value": 366, "color": "hsl(286, 70%, 50%)" }
15 | ]
16 |
17 | def __init__(self, *args, **kwargs):
18 | super().__init__(*args, **kwargs)
19 | self._theme = {
20 | "dark": {
21 | "background": "#252526",
22 | "textColor": "#FAFAFA",
23 | "tooltip": {
24 | "container": {
25 | "background": "#3F3F3F",
26 | "color": "FAFAFA",
27 | }
28 | }
29 | },
30 | "light": {
31 | "background": "#FFFFFF",
32 | "textColor": "#31333F",
33 | "tooltip": {
34 | "container": {
35 | "background": "#FFFFFF",
36 | "color": "#31333F",
37 | }
38 | }
39 | }
40 | }
41 |
42 | def __call__(self, json_data):
43 | try:
44 | data = json.loads(json_data)
45 | except json.JSONDecodeError:
46 | data = self.DEFAULT_DATA
47 |
48 | with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
49 | with self.title_bar():
50 | mui.icon.PieChart()
51 | mui.Typography("Pie chart", sx={"flex": 1})
52 |
53 | with mui.Box(sx={"flex": 1, "minHeight": 0}):
54 | nivo.Pie(
55 | data=data,
56 | theme=self._theme["dark" if self._dark_mode else "light"],
57 | margin={ "top": 40, "right": 80, "bottom": 80, "left": 80 },
58 | innerRadius=0.5,
59 | padAngle=0.7,
60 | cornerRadius=3,
61 | activeOuterRadiusOffset=8,
62 | borderWidth=1,
63 | borderColor={
64 | "from": "color",
65 | "modifiers": [
66 | [
67 | "darker",
68 | 0.2,
69 | ]
70 | ]
71 | },
72 | arcLinkLabelsSkipAngle=10,
73 | arcLinkLabelsTextColor="grey",
74 | arcLinkLabelsThickness=2,
75 | arcLinkLabelsColor={ "from": "color" },
76 | arcLabelsSkipAngle=10,
77 | arcLabelsTextColor={
78 | "from": "color",
79 | "modifiers": [
80 | [
81 | "darker",
82 | 2
83 | ]
84 | ]
85 | },
86 | defs=[
87 | {
88 | "id": "dots",
89 | "type": "patternDots",
90 | "background": "inherit",
91 | "color": "rgba(255, 255, 255, 0.3)",
92 | "size": 4,
93 | "padding": 1,
94 | "stagger": True
95 | },
96 | {
97 | "id": "lines",
98 | "type": "patternLines",
99 | "background": "inherit",
100 | "color": "rgba(255, 255, 255, 0.3)",
101 | "rotation": -45,
102 | "lineWidth": 6,
103 | "spacing": 10
104 | }
105 | ],
106 | fill=[
107 | { "match": { "id": "ruby" }, "id": "dots" },
108 | { "match": { "id": "c" }, "id": "dots" },
109 | { "match": { "id": "go" }, "id": "dots" },
110 | { "match": { "id": "python" }, "id": "dots" },
111 | { "match": { "id": "scala" }, "id": "lines" },
112 | { "match": { "id": "lisp" }, "id": "lines" },
113 | { "match": { "id": "elixir" }, "id": "lines" },
114 | { "match": { "id": "javascript" }, "id": "lines" }
115 | ],
116 | legends=[
117 | {
118 | "anchor": "bottom",
119 | "direction": "row",
120 | "justify": False,
121 | "translateX": 0,
122 | "translateY": 56,
123 | "itemsSpacing": 0,
124 | "itemWidth": 100,
125 | "itemHeight": 18,
126 | "itemTextColor": "#999",
127 | "itemDirection": "left-to-right",
128 | "itemOpacity": 1,
129 | "symbolSize": 18,
130 | "symbolShape": "circle",
131 | "effects": [
132 | {
133 | "on": "hover",
134 | "style": {
135 | "itemTextColor": "#000"
136 | }
137 | }
138 | ]
139 | }
140 | ]
141 | )
142 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/player.py:
--------------------------------------------------------------------------------
1 | from streamlit_elements import media, mui, sync, lazy
2 | from .dashboard import Dashboard
3 |
4 | class Player(Dashboard.Item):
5 |
6 | def __init__(self, *args, **kwargs):
7 | super().__init__(*args, **kwargs)
8 | self._url = "https://www.youtube.com/watch?v=CmSKVW1v0xM"
9 |
10 | def _set_url(self, event):
11 | self._url = event.target.value
12 |
13 | def __call__(self):
14 | with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
15 | with self.title_bar(padding="10px 15px 10px 15px", dark_switcher=False):
16 | mui.icon.OndemandVideo()
17 | mui.Typography("Media player")
18 |
19 | with mui.Stack(direction="row", spacing=2, justifyContent="space-evenly", alignItems="center", sx={"padding": "10px"}):
20 | mui.TextField(defaultValue=self._url, label="URL", variant="standard", sx={"flex": 0.97}, onChange=lazy(self._set_url))
21 | mui.IconButton(mui.icon.PlayCircleFilled, onClick=sync(), sx={"color": "primary.main"})
22 |
23 | media.Player(self._url, controls=True, width="100%", height="100%")
24 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/dashboard/radar.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from streamlit_elements import mui, nivo
4 | from .dashboard import Dashboard
5 |
6 |
7 | class Radar(Dashboard.Item):
8 |
9 | DEFAULT_DATA = [
10 | { "taste": "fruity", "chardonay": 93, "carmenere": 61, "syrah": 114 },
11 | { "taste": "bitter", "chardonay": 91, "carmenere": 37, "syrah": 72 },
12 | { "taste": "heavy", "chardonay": 56, "carmenere": 95, "syrah": 99 },
13 | { "taste": "strong", "chardonay": 64, "carmenere": 90, "syrah": 30 },
14 | { "taste": "sunny", "chardonay": 119, "carmenere": 94, "syrah": 103 },
15 | ]
16 |
17 | def __init__(self, *args, **kwargs):
18 | super().__init__(*args, **kwargs)
19 | self._theme = {
20 | "dark": {
21 | "background": "#252526",
22 | "textColor": "#FAFAFA",
23 | "tooltip": {
24 | "container": {
25 | "background": "#3F3F3F",
26 | "color": "FAFAFA",
27 | }
28 | }
29 | },
30 | "light": {
31 | "background": "#FFFFFF",
32 | "textColor": "#31333F",
33 | "tooltip": {
34 | "container": {
35 | "background": "#FFFFFF",
36 | "color": "#31333F",
37 | }
38 | }
39 | }
40 | }
41 |
42 | def __call__(self, json_data):
43 | try:
44 | data = json.loads(json_data)
45 | except json.JSONDecodeError:
46 | data = self.DEFAULT_DATA
47 |
48 | with mui.Paper(key=self._key, sx={"display": "flex", "flexDirection": "column", "borderRadius": 3, "overflow": "hidden"}, elevation=1):
49 | with self.title_bar():
50 | mui.icon.Radar()
51 | mui.Typography("Radar chart", sx={"flex": 1})
52 |
53 | with mui.Box(sx={"flex": 1, "minHeight": 0}):
54 | nivo.Radar(
55 | data=data,
56 | theme=self._theme["dark" if self._dark_mode else "light"],
57 | keys=[ "chardonay", "carmenere", "syrah" ],
58 | indexBy="taste",
59 | valueFormat=">-.2f",
60 | margin={ "top": 70, "right": 80, "bottom": 40, "left": 80 },
61 | borderColor={ "from": "color" },
62 | gridLabelOffset=36,
63 | dotSize=10,
64 | dotColor={ "theme": "background" },
65 | dotBorderWidth=2,
66 | motionConfig="wobbly",
67 | legends=[
68 | {
69 | "anchor": "top-left",
70 | "direction": "column",
71 | "translateX": -50,
72 | "translateY": -40,
73 | "itemWidth": 80,
74 | "itemHeight": 20,
75 | "itemTextColor": "#999",
76 | "symbolSize": 12,
77 | "symbolShape": "circle",
78 | "effects": [
79 | {
80 | "on": "hover",
81 | "style": {
82 | "itemTextColor": "#000"
83 | }
84 | }
85 | ]
86 | }
87 | ]
88 | )
89 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/elements/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import json
2 | import streamlit as st
3 |
4 | from pathlib import Path
5 | from streamlit import session_state as state
6 | from streamlit_elements import elements, sync, event
7 | from types import SimpleNamespace
8 |
9 | from .dashboard import Dashboard, Editor, Card, DataGrid, Radar, Pie, Player
10 |
11 |
12 | def main():
13 | st.write(
14 | """
15 | ✨ Streamlit Elements [![GitHub][github_badge]][github_link] [![PyPI][pypi_badge]][pypi_link]
16 | =====================
17 |
18 | Create a draggable and resizable dashboard in Streamlit, featuring Material UI widgets,
19 | Monaco editor (Visual Studio Code), Nivo charts, and more!
20 |
21 | [github_badge]: https://badgen.net/badge/icon/GitHub?icon=github&color=black&label
22 | [github_link]: https://github.com/okld/streamlit-elements
23 |
24 | [pypi_badge]: https://badgen.net/pypi/v/streamlit-elements?icon=pypi&color=black&label
25 | [pypi_link]: https://pypi.org/project/streamlit-elements
26 | """
27 | )
28 |
29 | with st.expander("GETTING STARTED"):
30 | st.write((Path(__file__).parent/"README.md").read_text())
31 |
32 | st.title("")
33 |
34 | if "w" not in state:
35 | board = Dashboard()
36 | w = SimpleNamespace(
37 | dashboard=board,
38 | editor=Editor(board, 0, 0, 6, 11, minW=3, minH=3),
39 | player=Player(board, 0, 12, 6, 10, minH=5),
40 | pie=Pie(board, 6, 0, 6, 7, minW=3, minH=4),
41 | radar=Radar(board, 12, 7, 3, 7, minW=2, minH=4),
42 | card=Card(board, 6, 7, 3, 7, minW=2, minH=4),
43 | data_grid=DataGrid(board, 6, 13, 6, 7, minH=4),
44 | )
45 | state.w = w
46 |
47 | w.editor.add_tab("Card content", Card.DEFAULT_CONTENT, "plaintext")
48 | w.editor.add_tab("Data grid", json.dumps(DataGrid.DEFAULT_ROWS, indent=2), "json")
49 | w.editor.add_tab("Radar chart", json.dumps(Radar.DEFAULT_DATA, indent=2), "json")
50 | w.editor.add_tab("Pie chart", json.dumps(Pie.DEFAULT_DATA, indent=2), "json")
51 | else:
52 | w = state.w
53 |
54 | with elements("demo"):
55 | event.Hotkey("ctrl+s", sync(), bindInputs=True, overrideDefault=True)
56 |
57 | with w.dashboard(rowHeight=57):
58 | w.editor()
59 | w.player()
60 | w.pie(w.editor.get_content("Pie chart"))
61 | w.radar(w.editor.get_content("Radar chart"))
62 | w.card(w.editor.get_content("Card content"))
63 | w.data_grid(w.editor.get_content("Data grid"))
64 |
65 |
66 | if __name__ == "__main__":
67 | st.set_page_config(layout="wide")
68 | main()
69 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/pandas_profiling/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/pandas_profiling/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/pandas_profiling/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import pandas as pd
2 | import pandas_profiling
3 | import streamlit as st
4 |
5 | from streamlit_gallery.utils.readme import readme
6 | from streamlit_pandas_profiling import st_profile_report
7 |
8 |
9 | def main():
10 | with readme("streamlit-pandas-profiling", st_profile_report, __file__):
11 | dataset = "https://storage.googleapis.com/tf-datasets/titanic/train.csv"
12 |
13 | df = pd.read_csv(dataset)
14 | pr = gen_profile_report(df, explorative=True)
15 |
16 | st.write(f"🔗 [Titanic dataset]({dataset})")
17 | st.write(df)
18 |
19 | with st.expander("REPORT", expanded=True):
20 | st_profile_report(pr)
21 |
22 |
23 | @st.cache(allow_output_mutation=True)
24 | def gen_profile_report(df, *report_args, **report_kwargs):
25 | return df.profile_report(*report_args, **report_kwargs)
26 |
27 |
28 | if __name__ == "__main__":
29 | main()
30 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/quill_editor/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/quill_editor/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/quill_editor/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from streamlit_gallery.utils.readme import readme
4 | from streamlit_quill import st_quill
5 |
6 |
7 | def main():
8 | with readme("streamlit-quill", st_quill, __file__):
9 | c1, c2 = st.columns([3, 1])
10 |
11 | c2.subheader("Parameters")
12 |
13 | with c1:
14 | content = st_quill(
15 | placeholder="Write your text here",
16 | html=c2.checkbox("Return HTML", False),
17 | readonly=c2.checkbox("Read only", False),
18 | key="quill",
19 | )
20 |
21 | if content:
22 | st.subheader("Content")
23 | st.text(content)
24 |
25 |
26 | if __name__ == "__main__":
27 | main()
28 |
--------------------------------------------------------------------------------
/streamlit_gallery/components/react_player/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/components/react_player/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/components/react_player/streamlit_app.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | from streamlit_player import st_player, _SUPPORTED_EVENTS
4 | from streamlit_gallery.utils.readme import readme
5 |
6 |
7 | def main():
8 | with readme("streamlit-player", st_player, __file__):
9 | c1, c2, c3 = st.columns([3, 3, 2])
10 |
11 | with c3:
12 | st.subheader("Parameters")
13 |
14 | options = {
15 | "events": st.multiselect("Events to listen", _SUPPORTED_EVENTS, ["onProgress"]),
16 | "progress_interval": 1000,
17 | "volume": st.slider("Volume", 0.0, 1.0, 1.0, .01),
18 | "playing": st.checkbox("Playing", False),
19 | "loop": st.checkbox("Loop", False),
20 | "controls": st.checkbox("Controls", True),
21 | "muted": st.checkbox("Muted", False),
22 | }
23 |
24 | with st.expander("SUPPORTED PLAYERS", expanded=True):
25 | st.write("""
26 | - Dailymotion
27 | - Facebook
28 | - Mixcloud
29 | - SoundCloud
30 | - Streamable
31 | - Twitch
32 | - Vimeo
33 | - Wistia
34 | - YouTube
35 |
36 | """, unsafe_allow_html=True)
37 |
38 |
39 | with c1:
40 | url = st.text_input("First URL", "https://youtu.be/c9k8K1eII4g")
41 | event = st_player(url, **options, key="youtube_player")
42 |
43 | st.write(event)
44 |
45 | with c2:
46 | url = st.text_input("Second URL", "https://soundcloud.com/imaginedragons/demons")
47 | event = st_player(url, **options, key="soundcloud_player")
48 |
49 | st.write(event)
50 |
51 |
52 | if __name__ == "__main__":
53 | main()
54 |
--------------------------------------------------------------------------------
/streamlit_gallery/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/okld/streamlit-gallery/ad224abfd5c2bc43a2937fa17c6f392672330688/streamlit_gallery/utils/__init__.py
--------------------------------------------------------------------------------
/streamlit_gallery/utils/page.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from typing import Callable, Optional
3 |
4 |
5 | def page_group(param):
6 | key = f"{__name__}_page_group_{param}"
7 |
8 | if key not in st.session_state:
9 | st.session_state[key] = PageGroup(param)
10 |
11 | return st.session_state[key]
12 |
13 |
14 | class PageGroup:
15 |
16 | def __init__(self, param):
17 | self._param: str = param
18 | self._default: str = None
19 | self._selected: str = None
20 |
21 | # Fix some rollback issues when multiple pages are selected in the same run.
22 | self._backup: Optional[str] = None
23 |
24 | @property
25 | def selected(self) -> bool:
26 | params = st.experimental_get_query_params()
27 | return params[self._param][0] if self._param in params else self._default
28 |
29 | def item(self, label: str, callback: Callable, default=False) -> None:
30 | self._backup = None
31 |
32 | key = f"{__name__}_{self._param}_{label}"
33 | page = self._normalize_label(label)
34 |
35 | if default:
36 | self._default = page
37 |
38 | selected = (page == self.selected)
39 |
40 | if selected:
41 | self._selected = callback
42 |
43 | st.session_state[key] = selected
44 | st.checkbox(label, key=key, disabled=selected, on_change=self._on_change, args=(page,))
45 |
46 | def show(self) -> None:
47 | if self._selected is not None:
48 | self._selected()
49 | else:
50 | st.title("🤷 404 Not Found")
51 |
52 | def _on_change(self, page: str) -> None:
53 | params = st.experimental_get_query_params()
54 |
55 | if self._backup is None:
56 | if self._param in params:
57 | self._backup = params[self._param][0]
58 | params[self._param] = [page]
59 | else:
60 | params[self._param] = [self._backup]
61 |
62 | st.experimental_set_query_params(**params)
63 |
64 | def _normalize_label(self, label: str) -> str:
65 | return "".join(char.lower() for char in label if char.isascii()).strip().replace(" ", "-")
66 |
--------------------------------------------------------------------------------
/streamlit_gallery/utils/readme.py:
--------------------------------------------------------------------------------
1 | import re
2 | import requests
3 | import streamlit as st
4 |
5 | from contextlib import contextmanager
6 | from pathlib import Path
7 |
8 | FILTER_SHARE = re.compile(r"^.*\[share_\w+\].*$", re.MULTILINE)
9 |
10 |
11 | @contextmanager
12 | def readme(project, usage=None, source=None):
13 | content = requests.get(f"https://raw.githubusercontent.com/okld/{project}/main/README.md").text
14 | st.markdown(FILTER_SHARE.sub("", content))
15 |
16 | demo = st.container()
17 |
18 | if usage or source:
19 | st.title("")
20 |
21 | if usage:
22 | with st.expander("USAGE"):
23 | st.help(usage)
24 |
25 | if source:
26 | with st.expander("SOURCE"):
27 | st.code(Path(source).read_text())
28 |
29 | with demo:
30 | yield
31 |
--------------------------------------------------------------------------------