streamlit 1.50.0__py3-none-any.whl → 1.51.0__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 (232) hide show
  1. streamlit/__init__.py +4 -1
  2. streamlit/commands/navigation.py +4 -6
  3. streamlit/commands/page_config.py +4 -6
  4. streamlit/components/v2/__init__.py +458 -0
  5. streamlit/components/v2/bidi_component/__init__.py +20 -0
  6. streamlit/components/v2/bidi_component/constants.py +29 -0
  7. streamlit/components/v2/bidi_component/main.py +386 -0
  8. streamlit/components/v2/bidi_component/serialization.py +265 -0
  9. streamlit/components/v2/bidi_component/state.py +92 -0
  10. streamlit/components/v2/component_definition_resolver.py +143 -0
  11. streamlit/components/v2/component_file_watcher.py +403 -0
  12. streamlit/components/v2/component_manager.py +431 -0
  13. streamlit/components/v2/component_manifest_handler.py +122 -0
  14. streamlit/components/v2/component_path_utils.py +245 -0
  15. streamlit/components/v2/component_registry.py +409 -0
  16. streamlit/components/v2/get_bidi_component_manager.py +51 -0
  17. streamlit/components/v2/manifest_scanner.py +615 -0
  18. streamlit/components/v2/presentation.py +198 -0
  19. streamlit/components/v2/types.py +324 -0
  20. streamlit/config.py +456 -53
  21. streamlit/config_option.py +4 -1
  22. streamlit/config_util.py +650 -1
  23. streamlit/dataframe_util.py +15 -8
  24. streamlit/delta_generator.py +6 -4
  25. streamlit/delta_generator_singletons.py +3 -1
  26. streamlit/deprecation_util.py +17 -6
  27. streamlit/elements/arrow.py +37 -9
  28. streamlit/elements/deck_gl_json_chart.py +97 -39
  29. streamlit/elements/dialog_decorator.py +2 -1
  30. streamlit/elements/exception.py +3 -1
  31. streamlit/elements/graphviz_chart.py +1 -3
  32. streamlit/elements/heading.py +3 -5
  33. streamlit/elements/image.py +2 -4
  34. streamlit/elements/layouts.py +31 -11
  35. streamlit/elements/lib/built_in_chart_utils.py +1 -3
  36. streamlit/elements/lib/color_util.py +8 -18
  37. streamlit/elements/lib/column_config_utils.py +4 -8
  38. streamlit/elements/lib/column_types.py +40 -12
  39. streamlit/elements/lib/dialog.py +2 -2
  40. streamlit/elements/lib/image_utils.py +3 -5
  41. streamlit/elements/lib/layout_utils.py +50 -13
  42. streamlit/elements/lib/mutable_status_container.py +2 -2
  43. streamlit/elements/lib/options_selector_utils.py +2 -2
  44. streamlit/elements/lib/utils.py +4 -4
  45. streamlit/elements/map.py +80 -37
  46. streamlit/elements/media.py +5 -7
  47. streamlit/elements/metric.py +3 -5
  48. streamlit/elements/pdf.py +2 -4
  49. streamlit/elements/plotly_chart.py +125 -17
  50. streamlit/elements/progress.py +2 -4
  51. streamlit/elements/space.py +113 -0
  52. streamlit/elements/vega_charts.py +339 -148
  53. streamlit/elements/widgets/audio_input.py +5 -5
  54. streamlit/elements/widgets/button.py +2 -4
  55. streamlit/elements/widgets/button_group.py +33 -7
  56. streamlit/elements/widgets/camera_input.py +2 -4
  57. streamlit/elements/widgets/chat.py +7 -1
  58. streamlit/elements/widgets/color_picker.py +1 -1
  59. streamlit/elements/widgets/data_editor.py +28 -24
  60. streamlit/elements/widgets/file_uploader.py +5 -10
  61. streamlit/elements/widgets/multiselect.py +4 -3
  62. streamlit/elements/widgets/number_input.py +2 -4
  63. streamlit/elements/widgets/radio.py +10 -3
  64. streamlit/elements/widgets/select_slider.py +8 -5
  65. streamlit/elements/widgets/selectbox.py +6 -3
  66. streamlit/elements/widgets/slider.py +38 -42
  67. streamlit/elements/widgets/time_widgets.py +6 -12
  68. streamlit/elements/write.py +27 -6
  69. streamlit/emojis.py +1 -1
  70. streamlit/errors.py +115 -0
  71. streamlit/hello/hello.py +8 -0
  72. streamlit/hello/utils.py +2 -1
  73. streamlit/material_icon_names.py +1 -1
  74. streamlit/navigation/page.py +4 -1
  75. streamlit/proto/ArrowData_pb2.py +27 -0
  76. streamlit/proto/ArrowData_pb2.pyi +46 -0
  77. streamlit/proto/BidiComponent_pb2.py +34 -0
  78. streamlit/proto/BidiComponent_pb2.pyi +153 -0
  79. streamlit/proto/Block_pb2.py +7 -7
  80. streamlit/proto/Block_pb2.pyi +4 -1
  81. streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
  82. streamlit/proto/DeckGlJsonChart_pb2.pyi +9 -3
  83. streamlit/proto/Element_pb2.py +5 -3
  84. streamlit/proto/Element_pb2.pyi +14 -4
  85. streamlit/proto/HeightConfig_pb2.py +2 -2
  86. streamlit/proto/HeightConfig_pb2.pyi +6 -3
  87. streamlit/proto/NewSession_pb2.py +18 -18
  88. streamlit/proto/NewSession_pb2.pyi +25 -6
  89. streamlit/proto/PlotlyChart_pb2.py +8 -6
  90. streamlit/proto/PlotlyChart_pb2.pyi +3 -1
  91. streamlit/proto/Space_pb2.py +27 -0
  92. streamlit/proto/Space_pb2.pyi +42 -0
  93. streamlit/proto/WidgetStates_pb2.py +2 -2
  94. streamlit/proto/WidgetStates_pb2.pyi +13 -3
  95. streamlit/proto/WidthConfig_pb2.py +2 -2
  96. streamlit/proto/WidthConfig_pb2.pyi +6 -3
  97. streamlit/runtime/app_session.py +27 -1
  98. streamlit/runtime/caching/cache_data_api.py +4 -4
  99. streamlit/runtime/caching/cache_errors.py +4 -1
  100. streamlit/runtime/caching/cache_resource_api.py +3 -2
  101. streamlit/runtime/caching/cache_utils.py +2 -1
  102. streamlit/runtime/caching/cached_message_replay.py +3 -3
  103. streamlit/runtime/caching/hashing.py +3 -4
  104. streamlit/runtime/caching/legacy_cache_api.py +2 -1
  105. streamlit/runtime/connection_factory.py +1 -3
  106. streamlit/runtime/forward_msg_queue.py +4 -1
  107. streamlit/runtime/fragment.py +2 -1
  108. streamlit/runtime/memory_media_file_storage.py +1 -1
  109. streamlit/runtime/metrics_util.py +6 -2
  110. streamlit/runtime/runtime.py +14 -0
  111. streamlit/runtime/scriptrunner/exec_code.py +2 -1
  112. streamlit/runtime/scriptrunner/script_runner.py +2 -2
  113. streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
  114. streamlit/runtime/secrets.py +2 -4
  115. streamlit/runtime/session_manager.py +3 -1
  116. streamlit/runtime/state/common.py +30 -5
  117. streamlit/runtime/state/presentation.py +85 -0
  118. streamlit/runtime/state/safe_session_state.py +2 -2
  119. streamlit/runtime/state/session_state.py +220 -16
  120. streamlit/runtime/state/widgets.py +19 -3
  121. streamlit/runtime/websocket_session_manager.py +3 -1
  122. streamlit/source_util.py +2 -2
  123. streamlit/static/index.html +2 -2
  124. streamlit/static/manifest.json +243 -226
  125. streamlit/static/static/css/{index.CIiu7Ygf.css → index.BpABIXK9.css} +1 -1
  126. streamlit/static/static/css/index.DgR7E2CV.css +1 -0
  127. streamlit/static/static/js/{ErrorOutline.esm.DUpR0_Ka.js → ErrorOutline.esm.YoJdlW1p.js} +1 -1
  128. streamlit/static/static/js/{FileDownload.esm.CN4j9-1w.js → FileDownload.esm.Ddx8VEYy.js} +1 -1
  129. streamlit/static/static/js/{FileHelper.CaIUKG91.js → FileHelper.90EtOmj9.js} +1 -1
  130. streamlit/static/static/js/{FormClearHelper.DTcdrasw.js → FormClearHelper.BB1Km6eP.js} +1 -1
  131. streamlit/static/static/js/InputInstructions.jhH15PqV.js +1 -0
  132. streamlit/static/static/js/{Particles.CElH0XX2.js → Particles.DUsputn1.js} +1 -1
  133. streamlit/static/static/js/{ProgressBar.DetlP5aY.js → ProgressBar.DLY8H6nE.js} +1 -1
  134. streamlit/static/static/js/{Toolbar.C77ar7rq.js → Toolbar.D8nHCkuz.js} +1 -1
  135. streamlit/static/static/js/{base-input.BQft14La.js → base-input.CJGiNqed.js} +3 -3
  136. streamlit/static/static/js/{checkbox.yZOfXCeX.js → checkbox.Cpdd482O.js} +1 -1
  137. streamlit/static/static/js/{createSuper.Dh9w1cs8.js → createSuper.CuQIogbW.js} +1 -1
  138. streamlit/static/static/js/{data-grid-overlay-editor.DcuHuCyW.js → data-grid-overlay-editor.2Ufgxc6y.js} +1 -1
  139. streamlit/static/static/js/{downloader.MeHtkq8r.js → downloader.CN0K7xlu.js} +1 -1
  140. streamlit/static/static/js/{es6.VpBPGCnM.js → es6.BJcsVXQ0.js} +2 -2
  141. streamlit/static/static/js/{iframeResizer.contentWindow.yMw_ARIL.js → iframeResizer.contentWindow.XzUvQqcZ.js} +1 -1
  142. streamlit/static/static/js/index.B1ZQh4P1.js +1 -0
  143. streamlit/static/static/js/index.BKstZk0M.js +27 -0
  144. streamlit/static/static/js/{index.Cnpi3o3E.js → index.BMcFsUee.js} +1 -1
  145. streamlit/static/static/js/{index.DKv_lNO7.js → index.BR-IdcTb.js} +1 -1
  146. streamlit/static/static/js/{index.FFOzOWzC.js → index.B_dWA3vd.js} +1 -1
  147. streamlit/static/static/js/{index.Bj9JgOEC.js → index.BgnZEMVh.js} +1 -1
  148. streamlit/static/static/js/{index.Bxz2yX3P.js → index.BohqXifI.js} +1 -1
  149. streamlit/static/static/js/{index.Dbe-Q3C-.js → index.Br5nxKNj.js} +1 -1
  150. streamlit/static/static/js/{index.BjCwMzj4.js → index.BrIKVbNc.js} +2 -2
  151. streamlit/static/static/js/index.BtWUPzle.js +1 -0
  152. streamlit/static/static/js/{index.CGYqqs6j.js → index.C0RLraek.js} +1 -1
  153. streamlit/static/static/js/{index.D2QEXQq_.js → index.CAIjskgG.js} +1 -1
  154. streamlit/static/static/js/{index.6xX1278W.js → index.CAj-7vWz.js} +131 -157
  155. streamlit/static/static/js/{index.DK7hD7_w.js → index.CMtEit2O.js} +1 -1
  156. streamlit/static/static/js/{index.DNLrMXgm.js → index.CkRlykEE.js} +1 -1
  157. streamlit/static/static/js/{index.ClELlchS.js → index.CmN3FXfI.js} +1 -1
  158. streamlit/static/static/js/{index.GRUzrudl.js → index.CwbFI1_-.js} +1 -1
  159. streamlit/static/static/js/{index.Ctn27_AE.js → index.CxIUUfab.js} +27 -27
  160. streamlit/static/static/js/index.D2KPNy7e.js +1 -0
  161. streamlit/static/static/js/{index.B0H9IXUJ.js → index.D3GPA5k4.js} +3 -3
  162. streamlit/static/static/js/{index.BycLveZ4.js → index.DGAh7DMq.js} +1 -1
  163. streamlit/static/static/js/index.DKb_NvmG.js +197 -0
  164. streamlit/static/static/js/{index.BPQo7BKk.js → index.DMqgUYKq.js} +1 -1
  165. streamlit/static/static/js/{index.CH1tqnSs.js → index.DOFlg3dS.js} +1 -1
  166. streamlit/static/static/js/{index.64ejlaaT.js → index.DPUXkcQL.js} +1 -1
  167. streamlit/static/static/js/{index.B-hiXRzw.js → index.DX1xY89g.js} +1 -1
  168. streamlit/static/static/js/index.DYATBCsq.js +2 -0
  169. streamlit/static/static/js/{index.DHh-U0dK.js → index.DaSmGJ76.js} +3 -3
  170. streamlit/static/static/js/{index.DuxqVQpd.js → index.Dd7bMeLP.js} +1 -1
  171. streamlit/static/static/js/{index.B4cAbHP6.js → index.DjmmgI5U.js} +1 -1
  172. streamlit/static/static/js/{index.DcPNYEUo.js → index.Dq56CyM2.js} +1 -1
  173. streamlit/static/static/js/{index.CiAQIz1H.js → index.DuiXaS5_.js} +1 -1
  174. streamlit/static/static/js/index.DvFidMLe.js +2 -0
  175. streamlit/static/static/js/{index.C9BdUqTi.js → index.DwkhC5Pc.js} +1 -1
  176. streamlit/static/static/js/{index.B4dUQfni.js → index.Q-3sFn1v.js} +1 -1
  177. streamlit/static/static/js/{index.CMItVsFA.js → index.QJ5QO9sJ.js} +1 -1
  178. streamlit/static/static/js/{index.CTBk8Vk2.js → index.VwTaeety.js} +1 -1
  179. streamlit/static/static/js/{index.Ck8rQ9OL.js → index.YOqQbeX8.js} +1 -1
  180. streamlit/static/static/js/{input.s6pjQ49A.js → input.D4MN_FzN.js} +1 -1
  181. streamlit/static/static/js/{memory.Cuvsdfrl.js → memory.DrZjtdGT.js} +1 -1
  182. streamlit/static/static/js/{number-overlay-editor.DdgVR5m3.js → number-overlay-editor.DRwAw1In.js} +1 -1
  183. streamlit/static/static/js/{possibleConstructorReturn.CqidKeei.js → possibleConstructorReturn.exeeJQEP.js} +1 -1
  184. streamlit/static/static/js/record.B-tDciZb.js +1 -0
  185. streamlit/static/static/js/{sandbox.CCQREcJx.js → sandbox.ClO3IuUr.js} +1 -1
  186. streamlit/static/static/js/{timepicker.mkJF97Bb.js → timepicker.DAhu-vcF.js} +1 -1
  187. streamlit/static/static/js/{toConsumableArray.De7I7KVR.js → toConsumableArray.DNbljYEC.js} +1 -1
  188. streamlit/static/static/js/{uniqueId.RI1LJdtz.js → uniqueId.oG4Gvj1v.js} +1 -1
  189. streamlit/static/static/js/{useBasicWidgetState.CedkNjUW.js → useBasicWidgetState.D6sOH6oI.js} +1 -1
  190. streamlit/static/static/js/{useTextInputAutoExpand.Ca7w8dVs.js → useTextInputAutoExpand.4u3_GcuN.js} +1 -1
  191. streamlit/static/static/js/{useUpdateUiValue.DeXelfRH.js → useUpdateUiValue.F2R3eTeR.js} +1 -1
  192. streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
  193. streamlit/static/static/js/{withFullScreenWrapper.C3561XxJ.js → withFullScreenWrapper.zothJIsI.js} +1 -1
  194. streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
  195. streamlit/string_util.py +1 -3
  196. streamlit/testing/v1/app_test.py +2 -2
  197. streamlit/testing/v1/element_tree.py +23 -9
  198. streamlit/testing/v1/util.py +2 -2
  199. streamlit/type_util.py +3 -4
  200. streamlit/url_util.py +1 -3
  201. streamlit/user_info.py +1 -2
  202. streamlit/util.py +3 -1
  203. streamlit/watcher/event_based_path_watcher.py +23 -12
  204. streamlit/watcher/local_sources_watcher.py +11 -1
  205. streamlit/watcher/path_watcher.py +9 -6
  206. streamlit/watcher/polling_path_watcher.py +4 -1
  207. streamlit/watcher/util.py +2 -2
  208. streamlit/web/cli.py +51 -22
  209. streamlit/web/server/bidi_component_request_handler.py +193 -0
  210. streamlit/web/server/component_file_utils.py +97 -0
  211. streamlit/web/server/component_request_handler.py +8 -21
  212. streamlit/web/server/oidc_mixin.py +3 -1
  213. streamlit/web/server/routes.py +2 -2
  214. streamlit/web/server/server.py +9 -0
  215. streamlit/web/server/server_util.py +3 -1
  216. streamlit/web/server/upload_file_request_handler.py +3 -1
  217. {streamlit-1.50.0.dist-info → streamlit-1.51.0.dist-info}/METADATA +4 -5
  218. {streamlit-1.50.0.dist-info → streamlit-1.51.0.dist-info}/RECORD +222 -194
  219. streamlit/static/static/css/index.CHEnSPGk.css +0 -1
  220. streamlit/static/static/js/Hooks.BRba_Own.js +0 -1
  221. streamlit/static/static/js/InputInstructions.xnSDuYeQ.js +0 -1
  222. streamlit/static/static/js/index.Baqa90pe.js +0 -2
  223. streamlit/static/static/js/index.Bm3VbPB5.js +0 -1
  224. streamlit/static/static/js/index.CFMf5_ez.js +0 -197
  225. streamlit/static/static/js/index.Cj7DSzVR.js +0 -73
  226. streamlit/static/static/js/index.DH71Ezyj.js +0 -1
  227. streamlit/static/static/js/index.DW0Grddz.js +0 -1
  228. streamlit/static/static/media/MaterialSymbols-Rounded.DeCZgS-4.woff2 +0 -0
  229. {streamlit-1.50.0.data → streamlit-1.51.0.data}/scripts/streamlit.cmd +0 -0
  230. {streamlit-1.50.0.dist-info → streamlit-1.51.0.dist-info}/WHEEL +0 -0
  231. {streamlit-1.50.0.dist-info → streamlit-1.51.0.dist-info}/entry_points.txt +0 -0
  232. {streamlit-1.50.0.dist-info → streamlit-1.51.0.dist-info}/top_level.txt +0 -0
streamlit/elements/pdf.py CHANGED
@@ -16,9 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import io
18
18
  from pathlib import Path
19
- from typing import TYPE_CHECKING, Any, Union, cast
20
-
21
- from typing_extensions import TypeAlias
19
+ from typing import TYPE_CHECKING, Any, TypeAlias, cast
22
20
 
23
21
  from streamlit import url_util
24
22
  from streamlit.elements.lib.layout_utils import validate_height
@@ -29,7 +27,7 @@ if TYPE_CHECKING:
29
27
  from streamlit.delta_generator import DeltaGenerator
30
28
  from streamlit.elements.lib.layout_utils import HeightWithoutContent
31
29
 
32
- PdfData: TypeAlias = Union[str, Path, bytes, io.BytesIO]
30
+ PdfData: TypeAlias = str | Path | bytes | io.BytesIO
33
31
 
34
32
 
35
33
  def _get_pdf_component() -> Any | None:
@@ -12,8 +12,6 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- """Streamlit support for Plotly charts."""
16
-
17
15
  from __future__ import annotations
18
16
 
19
17
  import json
@@ -23,23 +21,33 @@ from typing import (
23
21
  Any,
24
22
  Final,
25
23
  Literal,
24
+ TypeAlias,
26
25
  TypedDict,
27
26
  Union,
28
27
  cast,
29
28
  overload,
30
29
  )
31
30
 
32
- from typing_extensions import Required, TypeAlias
31
+ from typing_extensions import Required
33
32
 
34
33
  from streamlit import type_util
35
- from streamlit.deprecation_util import show_deprecation_warning
34
+ from streamlit.deprecation_util import (
35
+ make_deprecated_name_warning,
36
+ show_deprecation_warning,
37
+ )
36
38
  from streamlit.elements.lib.form_utils import current_form_id
39
+ from streamlit.elements.lib.layout_utils import (
40
+ LayoutConfig,
41
+ Width,
42
+ validate_width,
43
+ )
37
44
  from streamlit.elements.lib.policies import check_widget_policies
38
45
  from streamlit.elements.lib.streamlit_plotly_theme import (
39
46
  configure_streamlit_plotly_theme,
40
47
  )
41
48
  from streamlit.elements.lib.utils import Key, compute_and_register_element_id, to_key
42
49
  from streamlit.errors import StreamlitAPIException
50
+ from streamlit.logger import get_logger
43
51
  from streamlit.proto.PlotlyChart_pb2 import PlotlyChart as PlotlyChartProto
44
52
  from streamlit.runtime.metrics_util import gather_metrics
45
53
  from streamlit.runtime.scriptrunner_utils.script_run_context import get_script_run_ctx
@@ -76,6 +84,8 @@ FigureOrData: TypeAlias = Union[
76
84
  SelectionMode: TypeAlias = Literal["lasso", "points", "box"]
77
85
  _SELECTION_MODES: Final[set[SelectionMode]] = {"lasso", "points", "box"}
78
86
 
87
+ _LOGGER: Final = get_logger(__name__)
88
+
79
89
 
80
90
  class PlotlySelectionState(TypedDict, total=False):
81
91
  """
@@ -267,13 +277,61 @@ def parse_selection_mode(
267
277
  return set(parsed_selection_modes)
268
278
 
269
279
 
280
+ def _resolve_content_width(width: Width, figure: Any) -> Width:
281
+ """Resolve "content" width by inspecting the figure's layout width.
282
+
283
+ For content width, we check if the plotly figure has an explicit width
284
+ in its layout. If so, we use that as a pixel width. If not, we default
285
+ to 700 pixels which matches the plotly.js default width.
286
+
287
+ Args
288
+ ----
289
+ width : Width
290
+ The original width parameter
291
+ figure : Any
292
+ The plotly figure object (Figure, dict, or other supported formats)
293
+
294
+ Returns
295
+ -------
296
+ Width
297
+ The resolved width (either original width, figure width as pixels, or 700)
298
+ """
299
+
300
+ if width != "content":
301
+ return width
302
+
303
+ # Extract width from the figure's layout
304
+ # plotly.tools.mpl_to_plotly() returns Figure objects with .layout attribute
305
+ # plotly.tools.return_figure_from_figure_or_data() returns dictionaries
306
+ figure_width = None
307
+ if isinstance(figure, dict):
308
+ figure_width = figure.get("layout", {}).get("width")
309
+ else:
310
+ # Handle Figure objects from matplotlib conversion
311
+ try:
312
+ figure_width = figure.layout.width
313
+ except (AttributeError, TypeError):
314
+ _LOGGER.debug("Could not parse width from figure")
315
+
316
+ if (
317
+ figure_width is not None
318
+ and isinstance(figure_width, (int, float))
319
+ and figure_width > 0
320
+ ):
321
+ return int(figure_width)
322
+
323
+ # Default to 700 pixels (plotly.js default) when no width is specified
324
+ return 700
325
+
326
+
270
327
  class PlotlyMixin:
271
328
  @overload
272
329
  def plotly_chart(
273
330
  self,
274
331
  figure_or_data: FigureOrData,
275
- use_container_width: bool = True,
332
+ use_container_width: bool | None = None,
276
333
  *,
334
+ width: Width = "stretch",
277
335
  theme: Literal["streamlit"] | None = "streamlit",
278
336
  key: Key | None = None,
279
337
  on_select: Literal["ignore"], # No default value here to make it work with mypy
@@ -289,8 +347,9 @@ class PlotlyMixin:
289
347
  def plotly_chart(
290
348
  self,
291
349
  figure_or_data: FigureOrData,
292
- use_container_width: bool = True,
350
+ use_container_width: bool | None = None,
293
351
  *,
352
+ width: Width = "stretch",
294
353
  theme: Literal["streamlit"] | None = "streamlit",
295
354
  key: Key | None = None,
296
355
  on_select: Literal["rerun"] | WidgetCallback = "rerun",
@@ -306,8 +365,9 @@ class PlotlyMixin:
306
365
  def plotly_chart(
307
366
  self,
308
367
  figure_or_data: FigureOrData,
309
- use_container_width: bool = True,
368
+ use_container_width: bool | None = None,
310
369
  *,
370
+ width: Width = "stretch",
311
371
  theme: Literal["streamlit"] | None = "streamlit",
312
372
  key: Key | None = None,
313
373
  on_select: Literal["rerun", "ignore"] | WidgetCallback = "ignore",
@@ -357,13 +417,33 @@ class PlotlyMixin:
357
417
  render in SVG mode when passed to ``st.plotly_chart``:
358
418
  ``px.line(df, x="x", y="y", render_mode="svg")``.
359
419
 
360
- use_container_width : bool
420
+ width : "stretch", "content", or int
421
+ The width of the chart element. This can be one of the following:
422
+
423
+ - ``"stretch"`` (default): The width of the element matches the
424
+ width of the parent container.
425
+ - ``"content"``: The width of the element matches the width of its
426
+ content, but doesn't exceed the width of the parent container.
427
+ - An integer specifying the width in pixels: The element has a
428
+ fixed width. If the specified width is greater than the width of
429
+ the parent container, the width of the element matches the width
430
+ of the parent container.
431
+
432
+ use_container_width : bool or None
361
433
  Whether to override the figure's native width with the width of
362
- the parent container. If ``use_container_width`` is ``True`` (default),
363
- Streamlit sets the width of the figure to match the width of the parent
364
- container. If ``use_container_width`` is ``False``, Streamlit sets the
365
- width of the chart to fit its contents according to the plotting library,
366
- up to the width of the parent container.
434
+ the parent container. This can be one of the following:
435
+
436
+ - ``None`` (default): Streamlit will use the value of ``width``.
437
+ - ``True``: Streamlit sets the width of the figure to match the
438
+ width of the parent container.
439
+ - ``False``: Streamlit sets the width of the figure to fit its
440
+ contents according to the plotting library, up to the width of
441
+ the parent container.
442
+
443
+ .. deprecated::
444
+ ``use_container_width`` is deprecated and will be removed in a
445
+ future release. For ``use_container_width=True``, use
446
+ ``width="stretch"``.
367
447
 
368
448
  theme : "streamlit" or None
369
449
  The theme of the chart. If ``theme`` is ``"streamlit"`` (default),
@@ -497,6 +577,25 @@ class PlotlyMixin:
497
577
  height: 550px
498
578
 
499
579
  """
580
+ if use_container_width is not None:
581
+ show_deprecation_warning(
582
+ make_deprecated_name_warning(
583
+ "use_container_width",
584
+ "width",
585
+ "2025-12-31",
586
+ "For `use_container_width=True`, use `width='stretch'`. "
587
+ "For `use_container_width=False`, use `width='content'`.",
588
+ include_st_prefix=False,
589
+ ),
590
+ show_in_browser=False,
591
+ )
592
+ if use_container_width:
593
+ width = "stretch"
594
+ elif not isinstance(width, int):
595
+ width = "content"
596
+
597
+ validate_width(width, allow_content=True)
598
+
500
599
  import plotly.io
501
600
  import plotly.tools
502
601
 
@@ -549,7 +648,6 @@ class PlotlyMixin:
549
648
  )
550
649
 
551
650
  plotly_chart_proto = PlotlyChartProto()
552
- plotly_chart_proto.use_container_width = use_container_width
553
651
  plotly_chart_proto.theme = theme or ""
554
652
  plotly_chart_proto.form_id = current_form_id(self.dg)
555
653
 
@@ -572,9 +670,12 @@ class PlotlyMixin:
572
670
  selection_mode=selection_mode,
573
671
  is_selection_activated=is_selection_activated,
574
672
  theme=theme,
575
- use_container_width=use_container_width,
673
+ width=width,
576
674
  )
577
675
 
676
+ # Handle "content" width by inspecting the figure's natural width
677
+ final_width = _resolve_content_width(width, figure)
678
+
578
679
  if is_selection_activated:
579
680
  # Selections are activated, treat plotly chart as a widget:
580
681
  plotly_chart_proto.selection_mode.extend(
@@ -592,9 +693,16 @@ class PlotlyMixin:
592
693
  value_type="string_value",
593
694
  )
594
695
 
595
- self.dg._enqueue("plotly_chart", plotly_chart_proto)
696
+ layout_config = LayoutConfig(width=final_width)
697
+ self.dg._enqueue(
698
+ "plotly_chart", plotly_chart_proto, layout_config=layout_config
699
+ )
596
700
  return widget_state.value
597
- return self.dg._enqueue("plotly_chart", plotly_chart_proto)
701
+
702
+ layout_config = LayoutConfig(width=final_width)
703
+ return self.dg._enqueue(
704
+ "plotly_chart", plotly_chart_proto, layout_config=layout_config
705
+ )
598
706
 
599
707
  @property
600
708
  def dg(self) -> DeltaGenerator:
@@ -15,9 +15,7 @@
15
15
  from __future__ import annotations
16
16
 
17
17
  import math
18
- from typing import TYPE_CHECKING, Union, cast
19
-
20
- from typing_extensions import TypeAlias
18
+ from typing import TYPE_CHECKING, TypeAlias, cast
21
19
 
22
20
  from streamlit.elements.lib.layout_utils import LayoutConfig, validate_width
23
21
  from streamlit.errors import StreamlitAPIException
@@ -31,7 +29,7 @@ if TYPE_CHECKING:
31
29
 
32
30
  # Currently, equates to just float, but we can't use `numbers.Real` due to
33
31
  # https://github.com/python/mypy/issues/3186
34
- FloatOrInt: TypeAlias = Union[int, float]
32
+ FloatOrInt: TypeAlias = int | float
35
33
 
36
34
 
37
35
  def _check_float_between(value: float, low: float = 0.0, high: float = 1.0) -> bool:
@@ -0,0 +1,113 @@
1
+ # Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from __future__ import annotations
16
+
17
+ from typing import TYPE_CHECKING, cast
18
+
19
+ from streamlit.elements.lib.layout_utils import (
20
+ LayoutConfig,
21
+ SpaceSize,
22
+ validate_space_size,
23
+ )
24
+ from streamlit.proto.Space_pb2 import Space as SpaceProto
25
+ from streamlit.runtime.metrics_util import gather_metrics
26
+
27
+ if TYPE_CHECKING:
28
+ from streamlit.delta_generator import DeltaGenerator
29
+
30
+
31
+ class SpaceMixin:
32
+ @gather_metrics("space")
33
+ def space(
34
+ self,
35
+ size: SpaceSize = "small",
36
+ ) -> DeltaGenerator:
37
+ """Add vertical or horizontal space.
38
+
39
+ This command adds space in the direction of its parent container. In
40
+ a vertical layout, it adds vertical space. In a horizontal layout, it
41
+ adds horizontal space.
42
+
43
+ Parameters
44
+ ----------
45
+ size : "small", "medium", "large", "stretch", or int
46
+ The size of the space. This can be one of the following values:
47
+
48
+ - ``"small"`` (default): 0.75rem, which is the height of a widget
49
+ label. This is useful for aligning buttons with labeled widgets.
50
+ - ``"medium"``: 2.5rem, which is the height of a button or
51
+ (unlabeled) input field.
52
+ - ``"large"``: 4.25rem, which is the height of a labeled input
53
+ field or unlabeled media widget, like `st.file_uploader`.
54
+ - ``"stretch"``: Expands to fill remaining space in the container.
55
+ - An integer: Fixed size in pixels.
56
+
57
+ Examples
58
+ --------
59
+ **Example 1: Use vertical space to align elements**
60
+
61
+ Use small spaces to replace label heights. Use medium spaces to replace
62
+ two label heights or a button.
63
+
64
+ >>> import streamlit as st
65
+ >>>
66
+ >>> left, middle, right = st.columns(3)
67
+ >>>
68
+ >>> left.space("medium")
69
+ >>> left.button("Left button", width="stretch")
70
+ >>>
71
+ >>> middle.space("small")
72
+ >>> middle.text_input("Middle input")
73
+ >>>
74
+ >>> right.audio_input("Right uploader")
75
+
76
+ .. output::
77
+ https://doc-space-vertical.streamlit.app/
78
+ height: 260px
79
+
80
+ **Example 2: Add horizontal space in a container**
81
+
82
+ Use stretch space to float elements left and right.
83
+
84
+ >>> import streamlit as st
85
+ >>>
86
+ >>> with st.container(horizontal=True):
87
+ ... st.button("Left")
88
+ ... st.space("stretch")
89
+ ... st.button("Right")
90
+
91
+ .. output::
92
+ https://doc-space-horizontal.streamlit.app/
93
+ height: 200px
94
+
95
+ """
96
+ space_proto = SpaceProto()
97
+
98
+ validate_space_size(size)
99
+
100
+ # In vertical layouts, size controls height.
101
+ # In horizontal layouts, size controls width.
102
+ # We set both width and height configs to the same size value.
103
+ # The frontend uses FlexContext to determine container direction and
104
+ # applies ONLY the relevant dimension (width for horizontal, height for vertical)
105
+ # to avoid unintended cross-axis spacing.
106
+ layout_config = LayoutConfig(width=size, height=size)
107
+
108
+ return self.dg._enqueue("space", space_proto, layout_config=layout_config)
109
+
110
+ @property
111
+ def dg(self) -> DeltaGenerator:
112
+ """Get our DeltaGenerator."""
113
+ return cast("DeltaGenerator", self)