streamlit-nightly 1.35.1.dev20240612__py2.py3-none-any.whl → 1.35.1.dev20240614__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. streamlit/__init__.py +1 -1
  2. streamlit/commands/navigation.py +84 -18
  3. streamlit/components/v1/component_registry.py +24 -9
  4. streamlit/config.py +0 -3
  5. streamlit/elements/arrow.py +17 -6
  6. streamlit/elements/deck_gl_json_chart.py +1 -1
  7. streamlit/elements/dialog_decorator.py +5 -3
  8. streamlit/elements/html.py +1 -9
  9. streamlit/elements/iframe.py +53 -10
  10. streamlit/elements/layouts.py +66 -5
  11. streamlit/elements/lib/built_in_chart_utils.py +38 -10
  12. streamlit/elements/lib/column_types.py +1 -1
  13. streamlit/elements/lib/mutable_status_container.py +4 -4
  14. streamlit/elements/map.py +1 -1
  15. streamlit/elements/markdown.py +18 -14
  16. streamlit/elements/plotly_chart.py +5 -2
  17. streamlit/elements/toast.py +1 -1
  18. streamlit/elements/vega_charts.py +101 -39
  19. streamlit/elements/widgets/button.py +6 -3
  20. streamlit/elements/widgets/data_editor.py +1 -1
  21. streamlit/elements/widgets/file_uploader.py +1 -1
  22. streamlit/elements/write.py +11 -10
  23. streamlit/hello/Mapping_Demo.py +1 -1
  24. streamlit/navigation/page.py +107 -19
  25. streamlit/runtime/caching/cache_data_api.py +5 -4
  26. streamlit/runtime/caching/cache_errors.py +1 -1
  27. streamlit/runtime/caching/cache_resource_api.py +5 -4
  28. streamlit/runtime/caching/legacy_cache_api.py +13 -12
  29. streamlit/runtime/fragment.py +57 -27
  30. streamlit/runtime/runtime_util.py +1 -1
  31. streamlit/runtime/scriptrunner/script_run_context.py +1 -1
  32. streamlit/runtime/secrets.py +2 -2
  33. streamlit/runtime/state/session_state.py +1 -1
  34. streamlit/runtime/state/session_state_proxy.py +1 -1
  35. streamlit/static/asset-manifest.json +5 -5
  36. streamlit/static/index.html +1 -1
  37. streamlit/static/static/js/{4335.b492cdb7.chunk.js → 4335.f27a4b4a.chunk.js} +1 -1
  38. streamlit/static/static/js/{8427.59805a7f.chunk.js → 8427.5192ee0c.chunk.js} +1 -1
  39. streamlit/static/static/js/8536.f7b26b02.chunk.js +1 -0
  40. streamlit/static/static/js/main.7994a814.js +2 -0
  41. streamlit/testing/v1/app_test.py +4 -3
  42. streamlit/testing/v1/element_tree.py +2 -2
  43. streamlit/user_info.py +2 -4
  44. {streamlit_nightly-1.35.1.dev20240612.dist-info → streamlit_nightly-1.35.1.dev20240614.dist-info}/METADATA +9 -9
  45. {streamlit_nightly-1.35.1.dev20240612.dist-info → streamlit_nightly-1.35.1.dev20240614.dist-info}/RECORD +50 -50
  46. streamlit/static/static/js/8536.f8de3d9a.chunk.js +0 -1
  47. streamlit/static/static/js/main.0ebf040e.js +0 -2
  48. /streamlit/static/static/js/{main.0ebf040e.js.LICENSE.txt → main.7994a814.js.LICENSE.txt} +0 -0
  49. {streamlit_nightly-1.35.1.dev20240612.data → streamlit_nightly-1.35.1.dev20240614.data}/scripts/streamlit.cmd +0 -0
  50. {streamlit_nightly-1.35.1.dev20240612.dist-info → streamlit_nightly-1.35.1.dev20240614.dist-info}/WHEEL +0 -0
  51. {streamlit_nightly-1.35.1.dev20240612.dist-info → streamlit_nightly-1.35.1.dev20240614.dist-info}/entry_points.txt +0 -0
  52. {streamlit_nightly-1.35.1.dev20240612.dist-info → streamlit_nightly-1.35.1.dev20240614.dist-info}/top_level.txt +0 -0
streamlit/__init__.py CHANGED
@@ -244,7 +244,7 @@ experimental_singleton = _experimental_singleton
244
244
  experimental_user = _UserInfoProxy()
245
245
 
246
246
 
247
- _EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG = "Refer to our [docs page](https://docs.streamlit.io/library/api-reference/utilities/st.query_params) for more information."
247
+ _EXPERIMENTAL_QUERY_PARAMS_DEPRECATE_MSG = "Refer to our [docs page](https://docs.streamlit.io/develop/api-reference/caching-and-state/st.query_params) for more information."
248
248
 
249
249
  experimental_get_query_params = _deprecate_func_name(
250
250
  _get_query_params,
@@ -61,37 +61,103 @@ def navigation(
61
61
  """
62
62
  Configure the available pages in a multipage app.
63
63
 
64
- Call `st.navigation` in your main script with one or more pages defined by
65
- `st.Page`. `st.navigation` returns the current page which can be executed
66
- using `Page.run()`.
64
+ Call ``st.navigation`` in your entrypoint file with one or more pages
65
+ defined by ``st.Page``. ``st.navigation`` returns the current page, which
66
+ can be executed using ``.run()`` method.
67
67
 
68
- When using `st.navigation`, the main script is executed on every app rerun,
69
- with the current page executed in-line using `Page.run()`. The set of
70
- available pages can be updated with each rerun for dynamic navigation. In
71
- this mode, the `pages/` folder is ignored.
68
+ When using ``st.navigation``, your entrypoint file (the file passed to
69
+ ``streamlit run``) acts like a router or frame of common elements around
70
+ each of your pages. Streamlit executes the entrypoint file with every app
71
+ rerun. To execute the current page, you must call the ``.run()`` method on
72
+ the page object returned by ``st.navigation``.
72
73
 
73
- By default, `st.navigation` draws the available pages in the side
74
- navigation. This behavior can be changed using the `position=` keyword
75
- argument.
74
+ The set of available pages can be updated with each rerun for dynamic
75
+ navigation. By default, ``st.navigation`` draws the available pages in the
76
+ side navigation if there is more than one page. This behavior can be
77
+ changed using the ``position`` keyword argument.
78
+
79
+ As soon as any session of your app executes the ``st.navigation`` command,
80
+ your app will ignore the ``pages/`` directory (across all sessions).
76
81
 
77
82
  Parameters
78
83
  ----------
79
- pages: list[st.Page] or dict[str, list[st.Page]]
80
- A list of `st.Page` objects or a dictionary where the keys are section
81
- headers and the values are lists of `st.Page` objects.
84
+ pages: list[StreamlitPage] or dict[str, list[StreamlitPage]]
85
+ The available pages for the app.
86
+
87
+ To create labeled sections or page groupings within the navigation
88
+ menu, ``pages`` must be a dictionary. Each key is the label of a
89
+ section and each value is the list of ``StreamlitPage`` objects for
90
+ that section.
91
+
92
+ To create a navigation menu with no sections or page groupings,
93
+ ``pages`` must be a list of ``StreamlitPage`` objects.
94
+
95
+ Use ``st.Page`` to create ``StreamlitPage`` objects.
82
96
 
83
97
  position: "sidebar" or "hidden"
84
- The position of the navigation menu. Can be "sidebar" or "hidden".
98
+ The position of the navigation menu. If ``position`` is ``"sidebar"``
99
+ (default), the navigation widget appears at the top of the sidebar. If
100
+ ``position`` is ``"hidden"``, the navigation widget is not displayed.
101
+
102
+ If there is only one page in ``pages``, the navigation will be hidden
103
+ for any value of ``position``.
85
104
 
86
- Example
105
+ Returns
87
106
  -------
107
+ StreamlitPage
108
+ The current page selected by the user.
109
+
110
+ Examples
111
+ --------
112
+ The following examples show possible entrypoint files, which is the file
113
+ you pass to ``streamlit run``. Your entrypoint file manages your app's
114
+ navigation and serves as a router between pages.
115
+
116
+ You can declare pages from callables or file paths.
117
+
118
+ >>> import streamlit as st
119
+ >>> from page_functions import page1
120
+ >>>
121
+ >>> pg = st.navigation([st.Page(page1), st.Page("page2.py")])
122
+ >>> pg.run()
123
+
124
+ Use a dictionary to create sections within your navigation menu.
125
+
88
126
  >>> import streamlit as st
89
- >>> from pages import page1, page2
90
127
  >>>
91
- >>> pg = st.navigation([st.Page(page1), st.Page(page2)])
128
+ >>> pages = {
129
+ ... "Your account" : [
130
+ ... st.Page("create_account.py", title="Create your account"),
131
+ ... st.Page("manage_account.py", title="Manage your account")
132
+ ... ],
133
+ ... "Resources" : [
134
+ ... st.Page("learn.py", title="Learn about us"),
135
+ ... st.Page("trial.py", title="Try it out")
136
+ ... ]
137
+ ... }
92
138
  >>>
93
- >>> st.title("My Awesome App")
139
+ >>> pg = st.navigation(pages)
94
140
  >>> pg.run()
141
+
142
+ Call widget functions in your entrypoint file when you want a widget to be
143
+ stateful across pages. Assign keys to your common widgets and access their
144
+ values through Session State within your pages.
145
+
146
+ >>> import streamlit as st
147
+ >>>
148
+ >>> def page1():
149
+ >>> st.write(st.session_state.foo)
150
+ >>>
151
+ >>> def page2():
152
+ >>> st.write(st.session_state.bar)
153
+ >>>
154
+ >>> # Widgets shared by all the pages
155
+ >>> st.sidebar.selectbox("Foo", ["A", "B", "C"], key="foo")
156
+ >>> st.sidebar.checkbox("Bar", key="bar")
157
+ >>>
158
+ >>> pg = st.navigation(st.Page(page1), st.Page(page2))
159
+ >>> pg.run()
160
+
95
161
  """
96
162
  nav_sections = {"": pages} if isinstance(pages, list) else pages
97
163
  page_list = pages_from_nav_sections(nav_sections)
@@ -52,25 +52,40 @@ def declare_component(
52
52
  path: str | None = None,
53
53
  url: str | None = None,
54
54
  ) -> CustomComponent:
55
- """Create a custom component and register it if there is a ScriptRun context.
55
+ """Create a custom component and register it if there is a ``ScriptRunContext``.
56
56
 
57
- The component is not registered when there is no ScriptRun context; this can happen when CustomComponents are executed as standalone commands, e.g. for testing.
57
+ The component is not registered when there is no ``ScriptRunContext``.
58
+ This can happen when a ``CustomComponent`` is executed as standalone
59
+ command (e.g. for testing).
60
+
61
+ To use this function, import it from the ``streamlit.components.v1``
62
+ module.
63
+
64
+ .. warning::
65
+ Using ``st.components.v1.declare_component`` directly (instead of
66
+ importing its module) is deprecated and will be disallowd in a later
67
+ version.
58
68
 
59
69
  Parameters
60
70
  ----------
61
- name: str
62
- A short, descriptive name for the component. Like, "slider".
71
+ name : str
72
+ A short, descriptive name for the component, like "slider".
73
+
63
74
  path: str or None
64
- The path to serve the component's frontend files from. Either
65
- `path` or `url` must be specified, but not both.
75
+ The path to serve the component's frontend files from. If ``path`` is
76
+ ``None`` (default), Streamlit will server the component from the
77
+ location in ``url``. Either ``path`` or ``url`` must be specified, but
78
+ not both.
79
+
66
80
  url: str or None
67
- The URL that the component is served from. Either `path` or `url`
68
- must be specified, but not both.
81
+ The URL that the component is served from. If ``url`` is ``None``
82
+ (default), Streamlit will server the component from the location in
83
+ ``path``. Either ``path`` or ``url`` must be specified, but not both.
69
84
 
70
85
  Returns
71
86
  -------
72
87
  CustomComponent
73
- A CustomComponent that can be called like a function.
88
+ A ``CustomComponent`` that can be called like a function.
74
89
  Calling the component will create a new instance of the component
75
90
  in the Streamlit app.
76
91
 
streamlit/config.py CHANGED
@@ -465,9 +465,6 @@ _create_option(
465
465
  visibility="hidden",
466
466
  type_=bool,
467
467
  scriptable=True,
468
- deprecated=True,
469
- deprecation_text="logger.enableRich has been deprecated and will be removed in a future version. Exception formatting via rich will be automatically used if rich is enable.",
470
- expiration_date="2024-09-10",
471
468
  )
472
469
 
473
470
  # Config Section: Client #
@@ -95,12 +95,19 @@ class DataframeSelectionState(TypedDict, total=False):
95
95
  key and attribute notation. Selection states cannot be programmatically
96
96
  changed or set through Session State.
97
97
 
98
+ .. warning::
99
+ If a user sorts a dataframe, row selections will be reset. If your
100
+ users need to sort and filter the dataframe to make selections, direct
101
+ them to use the search function in the dataframe toolbar instead.
102
+
98
103
  Attributes
99
104
  ----------
100
105
  rows : list[int]
101
- The selected rows, identified by their positional index. The positional
102
- indices match the original dataframe, even if the user sorts the
103
- dataframe in their browser.
106
+ The selected rows, identified by their integer position. The integer
107
+ positions match the original dataframe, even if the user sorts the
108
+ dataframe in their browser. For a ``pandas.DataFrame``, you can
109
+ retrieve data from its interger position using methods like ``.iloc[]``
110
+ or ``.iat[]``.
104
111
  columns : list[str]
105
112
  The selected columns, identified by their names.
106
113
 
@@ -150,8 +157,12 @@ class DataframeState(TypedDict, total=False):
150
157
 
151
158
  Attributes
152
159
  ----------
153
- selection : DataframeSelectionState
154
- The state of the ``on_select`` event.
160
+ selection : dict
161
+ The state of the ``on_select`` event. This attribure returns a
162
+ dictionary-like object that supports both key and attribute notation.
163
+ The attributes are described by the ``DataframeSelectionState``
164
+ dictionary schema.
165
+
155
166
 
156
167
  """
157
168
 
@@ -346,7 +357,7 @@ class ArrowMixin:
346
357
  to change the displayed name of the column to "Dollar values"
347
358
  and add a "$" prefix in each cell. For more info on the
348
359
  available column types and config options, see
349
- `Column configuration <https://docs.streamlit.io/library/api-reference/data/st.column_config>`_.
360
+ `Column configuration <https://docs.streamlit.io/develop/api-reference/data/st.column_config>`_.
350
361
 
351
362
  To configure the index column(s), use ``_index`` as the column name.
352
363
 
@@ -66,7 +66,7 @@ class PydeckMixin:
66
66
 
67
67
  To get a token for yourself, create an account at https://mapbox.com.
68
68
  For more info on how to set config options, see
69
- https://docs.streamlit.io/library/advanced-features/configuration
69
+ https://docs.streamlit.io/develop/api-reference/configuration/config.toml.
70
70
 
71
71
  Parameters
72
72
  ----------
@@ -127,9 +127,11 @@ def dialog_decorator(
127
127
  handling any side effects of that behavior.
128
128
 
129
129
  .. warning::
130
- A dialog may not open another dialog. Only one dialog function may be
131
- called in a script run, which means that only one dialog can be open at
132
- any given time.
130
+ Only one dialog function may be called in a script run, which means
131
+ that only one dialog can be open at any given time. Since a dialog is
132
+ also a fragment, all fragment limitations apply. Dialogs can't contain
133
+ fragments, and fragments can't contain dialogs. Using dialogs in widget
134
+ callback functions is not supported.
133
135
 
134
136
  .. |st.experimental_fragment| replace:: ``st.experimental_fragment``
135
137
  .. _st.experimental_fragment: https://docs.streamlit.io/develop/api-reference/execution-flow/st.fragment
@@ -57,15 +57,7 @@ class HtmlMixin:
57
57
  -------
58
58
  >>> import streamlit as st
59
59
  >>>
60
- >>> code = \"""
61
- ... <style>
62
- ... p {
63
- ... color: red;
64
- ... }
65
- ... </style>
66
- ... \"""
67
- >>> st.html(code)
68
- >>> st.markdown("Lorem ipsum")
60
+ >>> st.html("<p><span style='text-decoration: line-through double red;'>Oops</span>!</p>")
69
61
 
70
62
  .. output::
71
63
  https://doc-html.streamlit.app/
@@ -34,18 +34,37 @@ class IframeMixin:
34
34
  ) -> DeltaGenerator:
35
35
  """Load a remote URL in an iframe.
36
36
 
37
+ To use this function, import it from the ``streamlit.components.v1``
38
+ module.
39
+
40
+ .. warning::
41
+ Using ``st.components.v1.iframe`` directly (instead of importing
42
+ its module) is deprecated and will be disallowd in a later version.
43
+
37
44
  Parameters
38
45
  ----------
39
46
  src : str
40
47
  The URL of the page to embed.
48
+
41
49
  width : int
42
- The width of the frame in CSS pixels. Defaults to the app's
43
- default element width.
50
+ The width of the iframe in CSS pixels. By default, this is the
51
+ app's default element width.
52
+
44
53
  height : int
45
- The height of the frame in CSS pixels. Defaults to 150.
54
+ The height of the frame in CSS pixels. By default, this is ``150``.
55
+
46
56
  scrolling : bool
47
- If True, show a scrollbar when the content is larger than the iframe.
48
- Otherwise, do not show a scrollbar. Defaults to False.
57
+ Whether to allow scrolling in the iframe. If this ``False``
58
+ (default), Streamlit crops any content larger than the iframe and
59
+ does not show a scrollbar. If this is ``True``, Streamlit shows a
60
+ scrollbar when the content is larger than the iframe.
61
+
62
+ Example
63
+ -------
64
+
65
+ >>> import streamlit.components.v1 as components
66
+ >>>
67
+ >>> components.iframe("https://example.com", height=500)
49
68
 
50
69
  """
51
70
  iframe_proto = IFrameProto()
@@ -68,18 +87,42 @@ class IframeMixin:
68
87
  ) -> DeltaGenerator:
69
88
  """Display an HTML string in an iframe.
70
89
 
90
+ To use this function, import it from the ``streamlit.components.v1``
91
+ module.
92
+
93
+ If you want to insert HTML text into your app without an iframe, try
94
+ ``st.html`` instead.
95
+
96
+ .. warning::
97
+ Using ``st.components.v1.html`` directly (instead of importing
98
+ its module) is deprecated and will be disallowd in a later version.
99
+
71
100
  Parameters
72
101
  ----------
73
102
  html : str
74
103
  The HTML string to embed in the iframe.
104
+
75
105
  width : int
76
- The width of the frame in CSS pixels. Defaults to the app's
77
- default element width.
106
+ The width of the iframe in CSS pixels. By default, this is the
107
+ app's default element width.
108
+
78
109
  height : int
79
- The height of the frame in CSS pixels. Defaults to 150.
110
+ The height of the frame in CSS pixels. By default, this is ``150``.
111
+
80
112
  scrolling : bool
81
- If True, show a scrollbar when the content is larger than the iframe.
82
- Otherwise, do not show a scrollbar. Defaults to False.
113
+ Whether to allow scrolling in the iframe. If this ``False``
114
+ (default), Streamlit crops any content larger than the iframe and
115
+ does not show a scrollbar. If this is ``True``, Streamlit shows a
116
+ scrollbar when the content is larger than the iframe.
117
+
118
+ Example
119
+ -------
120
+
121
+ >>> import streamlit.components.v1 as components
122
+ >>>
123
+ >>> components.html(
124
+ >>> "<p><span style='text-decoration: line-through double red;'>Oops</span>!</p>"
125
+ >>> )
83
126
 
84
127
  """
85
128
  iframe_proto = IFrameProto()
@@ -21,6 +21,7 @@ from typing_extensions import TypeAlias
21
21
  from streamlit.errors import StreamlitAPIException
22
22
  from streamlit.proto.Block_pb2 import Block as BlockProto
23
23
  from streamlit.runtime.metrics_util import gather_metrics
24
+ from streamlit.string_util import validate_icon_or_emoji
24
25
 
25
26
  if TYPE_CHECKING:
26
27
  from streamlit.delta_generator import DeltaGenerator
@@ -163,7 +164,8 @@ class LayoutsMixin:
163
164
  Columns can only be placed inside other columns up to one level of nesting.
164
165
 
165
166
  .. warning::
166
- Columns cannot be placed inside other columns in the sidebar. This is only possible in the main area of the app.
167
+ Columns cannot be placed inside other columns in the sidebar. This
168
+ is only possible in the main area of the app.
167
169
 
168
170
  Parameters
169
171
  ----------
@@ -179,10 +181,11 @@ class LayoutsMixin:
179
181
  the width of the first one, and the third one is three times that width.
180
182
 
181
183
  gap : "small", "medium", or "large"
182
- The size of the gap between the columns. Defaults to "small".
184
+ The size of the gap between the columns. The default is ``"small"``.
183
185
 
184
186
  vertical_alignment : "top", "center", or "bottom"
185
- The vertical alignment of the content inside the columns. Defaults to "top".
187
+ The vertical alignment of the content inside the columns. The
188
+ default is ``"top"``.
186
189
 
187
190
  Returns
188
191
  -------
@@ -231,6 +234,38 @@ class LayoutsMixin:
231
234
  https://doc-columns2.streamlit.app/
232
235
  height: 550px
233
236
 
237
+ Use ``vertical_alignment="bottom"`` to align widgets.
238
+
239
+ >>> import streamlit as st
240
+ >>>
241
+ >>> left, middle, right = st.columns(3, vertical_alignment="bottom")
242
+ >>>
243
+ >>> left.text_input("Write something")
244
+ >>> middle.button("Click me", use_container_width=True)
245
+ >>> right.checkbox("Check me")
246
+
247
+ .. output ::
248
+ https://doc-columns-bottom-widgets.streamlit.app/
249
+ height: 200px
250
+
251
+ Adjust vertical alignment to customize your grid layouts.
252
+
253
+ >>> import streamlit as st
254
+ >>> import numpy as np
255
+ >>>
256
+ >>> vertical_alignment = st.selectbox(
257
+ >>> "Vertical alignment", ["top", "center", "bottom"], index=2
258
+ >>> )
259
+ >>>
260
+ >>> left, middle, right = st.columns(3, vertical_alignment=vertical_alignment)
261
+ >>> left.image("https://static.streamlit.io/examples/cat.jpg")
262
+ >>> middle.image("https://static.streamlit.io/examples/dog.jpg")
263
+ >>> right.image("https://static.streamlit.io/examples/owl.jpg")
264
+
265
+ .. output ::
266
+ https://doc-columns-vertical-alignment.streamlit.app/
267
+ height: 600px
268
+
234
269
  """
235
270
  weights = spec
236
271
  if isinstance(weights, int):
@@ -243,7 +278,7 @@ class LayoutsMixin:
243
278
  raise StreamlitAPIException(
244
279
  "The input argument to st.columns must be either a "
245
280
  "positive integer or a list of positive numeric weights. "
246
- "See [documentation](https://docs.streamlit.io/library/api-reference/layout/st.columns) "
281
+ "See [documentation](https://docs.streamlit.io/develop/api-reference/layout/st.columns) "
247
282
  "for more information."
248
283
  )
249
284
 
@@ -408,7 +443,13 @@ class LayoutsMixin:
408
443
  return tuple(tab_container._block(tab_proto(tab_label)) for tab_label in tabs)
409
444
 
410
445
  @gather_metrics("expander")
411
- def expander(self, label: str, expanded: bool = False) -> DeltaGenerator:
446
+ def expander(
447
+ self,
448
+ label: str,
449
+ expanded: bool = False,
450
+ *,
451
+ icon: str | None = None,
452
+ ) -> DeltaGenerator:
412
453
  r"""Insert a multi-element container that can be expanded/collapsed.
413
454
 
414
455
  Inserts a container into your app that can be used to hold multiple elements
@@ -449,10 +490,28 @@ class LayoutsMixin:
449
490
  Unsupported elements are unwrapped so only their children (text contents) render.
450
491
  Display unsupported elements as literal characters by
451
492
  backslash-escaping them. E.g. ``1\. Not an ordered list``.
493
+
452
494
  expanded : bool
453
495
  If True, initializes the expander in "expanded" state. Defaults to
454
496
  False (collapsed).
455
497
 
498
+ icon : str, None
499
+ An optional emoji or icon to display next to the expander label. If ``icon``
500
+ is ``None`` (default), no icon is displayed. If ``icon`` is a
501
+ string, the following options are valid:
502
+
503
+ * A single-character emoji. For example, you can set ``icon="🚨"``
504
+ or ``icon="🔥"``. Emoji short codes are not supported.
505
+
506
+ * An icon from the Material Symbols library (outlined style) in the
507
+ format ``":material/icon_name:"`` where "icon_name" is the name
508
+ of the icon in snake case.
509
+
510
+ For example, ``icon=":material/thumb_up:"`` will display the
511
+ Thumb Up icon. Find additional icons in the `Material Symbols \
512
+ <https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Outlined>`_
513
+ font library.
514
+
456
515
  Examples
457
516
  --------
458
517
  You can use the ``with`` notation to insert any element into an expander
@@ -498,6 +557,8 @@ class LayoutsMixin:
498
557
  expandable_proto = BlockProto.Expandable()
499
558
  expandable_proto.expanded = expanded
500
559
  expandable_proto.label = label
560
+ if icon is not None:
561
+ expandable_proto.icon = validate_icon_or_emoji(icon)
501
562
 
502
563
  block_proto = BlockProto()
503
564
  block_proto.allow_empty = False
@@ -71,7 +71,8 @@ class AddRowsMetadata:
71
71
 
72
72
  class ChartType(Enum):
73
73
  AREA = {"mark_type": "area", "command": "area_chart"}
74
- BAR = {"mark_type": "bar", "command": "bar_chart"}
74
+ VERTICAL_BAR = {"mark_type": "bar", "command": "bar_chart", "horizontal": False}
75
+ HORIZONTAL_BAR = {"mark_type": "bar", "command": "bar_chart", "horizontal": True}
75
76
  LINE = {"mark_type": "line", "command": "line_chart"}
76
77
  SCATTER = {"mark_type": "circle", "command": "scatter_chart"}
77
78
 
@@ -165,6 +166,22 @@ def generate_chart(
165
166
 
166
167
  # At this point, x_column is only None if user did not provide one AND df is empty.
167
168
 
169
+ if chart_type == ChartType.HORIZONTAL_BAR:
170
+ # Handle horizontal bar chart - switches x and y data:
171
+ x_encoding = _get_x_encoding(
172
+ df, y_column, y_from_user, x_axis_label, chart_type
173
+ )
174
+ y_encoding = _get_y_encoding(
175
+ df, x_column, x_from_user, y_axis_label, chart_type
176
+ )
177
+ else:
178
+ x_encoding = _get_x_encoding(
179
+ df, x_column, x_from_user, x_axis_label, chart_type
180
+ )
181
+ y_encoding = _get_y_encoding(
182
+ df, y_column, y_from_user, y_axis_label, chart_type
183
+ )
184
+
168
185
  # Create a Chart with x and y encodings.
169
186
  chart = alt.Chart(
170
187
  data=df,
@@ -172,8 +189,8 @@ def generate_chart(
172
189
  width=width or 0,
173
190
  height=height or 0,
174
191
  ).encode(
175
- x=_get_x_encoding(df, x_column, x_from_user, x_axis_label, chart_type),
176
- y=_get_y_encoding(df, y_column, y_from_user, y_axis_label),
192
+ x=x_encoding,
193
+ y=y_encoding,
177
194
  )
178
195
 
179
196
  # Set up opacity encoding.
@@ -620,7 +637,7 @@ def _maybe_melt(
620
637
  def _get_x_encoding(
621
638
  df: pd.DataFrame,
622
639
  x_column: str | None,
623
- x_from_user: str | None,
640
+ x_from_user: str | Sequence[str] | None,
624
641
  x_axis_label: str | None,
625
642
  chart_type: ChartType,
626
643
  ) -> alt.X:
@@ -653,12 +670,15 @@ def _get_x_encoding(
653
670
  if x_axis_label is not None:
654
671
  x_title = x_axis_label
655
672
 
673
+ # grid lines on x axis for horizontal bar charts only
674
+ grid = True if chart_type == ChartType.HORIZONTAL_BAR else False
675
+
656
676
  return alt.X(
657
677
  x_field,
658
678
  title=x_title,
659
679
  type=_get_x_encoding_type(df, chart_type, x_column),
660
680
  scale=alt.Scale(),
661
- axis=_get_axis_config(df, x_column, grid=False),
681
+ axis=_get_axis_config(df, x_column, grid=grid),
662
682
  )
663
683
 
664
684
 
@@ -667,6 +687,7 @@ def _get_y_encoding(
667
687
  y_column: str | None,
668
688
  y_from_user: str | Sequence[str] | None,
669
689
  y_axis_label: str | None,
690
+ chart_type: ChartType,
670
691
  ) -> alt.Y:
671
692
  import altair as alt
672
693
 
@@ -697,12 +718,15 @@ def _get_y_encoding(
697
718
  if y_axis_label is not None:
698
719
  y_title = y_axis_label
699
720
 
721
+ # grid lines on y axis for all charts except horizontal bar charts
722
+ grid = False if chart_type == ChartType.HORIZONTAL_BAR else True
723
+
700
724
  return alt.Y(
701
725
  field=y_field,
702
726
  title=y_title,
703
- type=_get_y_encoding_type(df, y_column),
727
+ type=_get_y_encoding_type(df, chart_type, y_column),
704
728
  scale=alt.Scale(),
705
- axis=_get_axis_config(df, y_column, grid=True),
729
+ axis=_get_axis_config(df, y_column, grid=grid),
706
730
  )
707
731
 
708
732
 
@@ -877,17 +901,21 @@ def _get_x_encoding_type(
877
901
  if x_column is None:
878
902
  return "quantitative" # Anything. If None, Vega-Lite may hide the axis.
879
903
 
880
- # Bar charts should have a discrete (ordinal) x-axis, UNLESS type is date/time
904
+ # Vertical bar charts should have a discrete (ordinal) x-axis, UNLESS type is date/time
881
905
  # https://github.com/streamlit/streamlit/pull/2097#issuecomment-714802475
882
- if chart_type == ChartType.BAR and not _is_date_column(df, x_column):
906
+ if chart_type == ChartType.VERTICAL_BAR and not _is_date_column(df, x_column):
883
907
  return "ordinal"
884
908
 
885
909
  return type_util.infer_vegalite_type(df[x_column])
886
910
 
887
911
 
888
912
  def _get_y_encoding_type(
889
- df: pd.DataFrame, y_column: str | None
913
+ df: pd.DataFrame, chart_type: ChartType, y_column: str | None
890
914
  ) -> type_util.VegaLiteType:
915
+ # Horizontal bar charts should have a discrete (ordinal) y-axis, UNLESS type is date/time
916
+ if chart_type == ChartType.HORIZONTAL_BAR and not _is_date_column(df, y_column):
917
+ return "ordinal"
918
+
891
919
  if y_column:
892
920
  return type_util.infer_vegalite_type(df[y_column])
893
921
 
@@ -1038,7 +1038,7 @@ def ImageColumn(
1038
1038
  The cell values need to be one of:
1039
1039
 
1040
1040
  * A URL to fetch the image from. This can also be a relative URL of an image
1041
- deployed via `static file serving <https://docs.streamlit.io/library/advanced-features/static-file-serving>`_.
1041
+ deployed via `static file serving <https://docs.streamlit.io/develop/concepts/configuration/serving-static-files>`_.
1042
1042
  Note that you can NOT use an arbitrary local image if it is not available through
1043
1043
  a public URL.
1044
1044
  * A data URL containing an SVG XML like ``data:image/svg+xml;utf8,<svg xmlns=...</svg>``.
@@ -47,9 +47,9 @@ class StatusContainer(DeltaGenerator):
47
47
  if state == "running":
48
48
  expandable_proto.icon = "spinner"
49
49
  elif state == "complete":
50
- expandable_proto.icon = "check"
50
+ expandable_proto.icon = ":material/check:"
51
51
  elif state == "error":
52
- expandable_proto.icon = "error"
52
+ expandable_proto.icon = ":material/error:"
53
53
  else:
54
54
  raise StreamlitAPIException(
55
55
  f"Unknown state ({state}). Must be one of 'running', 'complete', or 'error'."
@@ -140,9 +140,9 @@ class StatusContainer(DeltaGenerator):
140
140
  if state == "running":
141
141
  msg.delta.add_block.expandable.icon = "spinner"
142
142
  elif state == "complete":
143
- msg.delta.add_block.expandable.icon = "check"
143
+ msg.delta.add_block.expandable.icon = ":material/check:"
144
144
  elif state == "error":
145
- msg.delta.add_block.expandable.icon = "error"
145
+ msg.delta.add_block.expandable.icon = ":material/error:"
146
146
  else:
147
147
  raise StreamlitAPIException(
148
148
  f"Unknown state ({state}). Must be one of 'running', 'complete', or 'error'."