streamlit 1.49.1__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 (259) hide show
  1. streamlit/__init__.py +4 -1
  2. streamlit/column_config.py +2 -0
  3. streamlit/commands/navigation.py +7 -7
  4. streamlit/commands/page_config.py +4 -6
  5. streamlit/components/v1/custom_component.py +17 -42
  6. streamlit/components/v2/__init__.py +458 -0
  7. streamlit/components/v2/bidi_component/__init__.py +20 -0
  8. streamlit/components/v2/bidi_component/constants.py +29 -0
  9. streamlit/components/v2/bidi_component/main.py +386 -0
  10. streamlit/components/v2/bidi_component/serialization.py +265 -0
  11. streamlit/components/v2/bidi_component/state.py +92 -0
  12. streamlit/components/v2/component_definition_resolver.py +143 -0
  13. streamlit/components/v2/component_file_watcher.py +403 -0
  14. streamlit/components/v2/component_manager.py +431 -0
  15. streamlit/components/v2/component_manifest_handler.py +122 -0
  16. streamlit/components/v2/component_path_utils.py +245 -0
  17. streamlit/components/v2/component_registry.py +409 -0
  18. streamlit/components/v2/get_bidi_component_manager.py +51 -0
  19. streamlit/components/v2/manifest_scanner.py +615 -0
  20. streamlit/components/v2/presentation.py +198 -0
  21. streamlit/components/v2/types.py +324 -0
  22. streamlit/config.py +741 -32
  23. streamlit/config_option.py +4 -1
  24. streamlit/config_util.py +650 -1
  25. streamlit/connections/base_connection.py +4 -2
  26. streamlit/dataframe_util.py +18 -10
  27. streamlit/delta_generator.py +8 -7
  28. streamlit/delta_generator_singletons.py +3 -1
  29. streamlit/deprecation_util.py +17 -6
  30. streamlit/elements/arrow.py +90 -42
  31. streamlit/elements/deck_gl_json_chart.py +98 -39
  32. streamlit/elements/dialog_decorator.py +2 -1
  33. streamlit/elements/exception.py +3 -1
  34. streamlit/elements/form.py +6 -6
  35. streamlit/elements/graphviz_chart.py +24 -9
  36. streamlit/elements/heading.py +3 -5
  37. streamlit/elements/iframe.py +0 -2
  38. streamlit/elements/image.py +12 -13
  39. streamlit/elements/layouts.py +89 -22
  40. streamlit/elements/lib/built_in_chart_utils.py +95 -31
  41. streamlit/elements/lib/color_util.py +8 -18
  42. streamlit/elements/lib/column_config_utils.py +9 -8
  43. streamlit/elements/lib/column_types.py +595 -148
  44. streamlit/elements/lib/dialog.py +3 -2
  45. streamlit/elements/lib/image_utils.py +3 -5
  46. streamlit/elements/lib/layout_utils.py +50 -13
  47. streamlit/elements/lib/mutable_status_container.py +2 -2
  48. streamlit/elements/lib/options_selector_utils.py +2 -2
  49. streamlit/elements/lib/pandas_styler_utils.py +30 -14
  50. streamlit/elements/lib/utils.py +21 -9
  51. streamlit/elements/map.py +81 -40
  52. streamlit/elements/media.py +7 -7
  53. streamlit/elements/metric.py +11 -35
  54. streamlit/elements/pdf.py +2 -4
  55. streamlit/elements/plotly_chart.py +142 -26
  56. streamlit/elements/progress.py +2 -4
  57. streamlit/elements/pyplot.py +6 -6
  58. streamlit/elements/space.py +113 -0
  59. streamlit/elements/vega_charts.py +400 -143
  60. streamlit/elements/widgets/audio_input.py +52 -4
  61. streamlit/elements/widgets/button.py +29 -29
  62. streamlit/elements/widgets/button_group.py +33 -6
  63. streamlit/elements/widgets/camera_input.py +3 -4
  64. streamlit/elements/widgets/chat.py +7 -0
  65. streamlit/elements/widgets/checkbox.py +1 -0
  66. streamlit/elements/widgets/color_picker.py +1 -0
  67. streamlit/elements/widgets/data_editor.py +34 -29
  68. streamlit/elements/widgets/file_uploader.py +6 -10
  69. streamlit/elements/widgets/multiselect.py +14 -3
  70. streamlit/elements/widgets/number_input.py +5 -4
  71. streamlit/elements/widgets/radio.py +10 -2
  72. streamlit/elements/widgets/select_slider.py +8 -4
  73. streamlit/elements/widgets/selectbox.py +9 -2
  74. streamlit/elements/widgets/slider.py +38 -41
  75. streamlit/elements/widgets/text_widgets.py +6 -0
  76. streamlit/elements/widgets/time_widgets.py +15 -12
  77. streamlit/elements/write.py +28 -23
  78. streamlit/emojis.py +1 -1
  79. streamlit/errors.py +115 -0
  80. streamlit/git_util.py +65 -43
  81. streamlit/hello/hello.py +8 -0
  82. streamlit/hello/utils.py +2 -1
  83. streamlit/material_icon_names.py +1 -1
  84. streamlit/navigation/page.py +4 -1
  85. streamlit/proto/ArrowData_pb2.py +27 -0
  86. streamlit/proto/ArrowData_pb2.pyi +46 -0
  87. streamlit/proto/Arrow_pb2.py +10 -8
  88. streamlit/proto/Arrow_pb2.pyi +31 -2
  89. streamlit/proto/AudioInput_pb2.py +2 -2
  90. streamlit/proto/AudioInput_pb2.pyi +6 -2
  91. streamlit/proto/BidiComponent_pb2.py +34 -0
  92. streamlit/proto/BidiComponent_pb2.pyi +153 -0
  93. streamlit/proto/Block_pb2.py +11 -11
  94. streamlit/proto/Block_pb2.pyi +9 -1
  95. streamlit/proto/DeckGlJsonChart_pb2.py +10 -4
  96. streamlit/proto/DeckGlJsonChart_pb2.pyi +9 -3
  97. streamlit/proto/Element_pb2.py +5 -3
  98. streamlit/proto/Element_pb2.pyi +14 -4
  99. streamlit/proto/HeightConfig_pb2.py +2 -2
  100. streamlit/proto/HeightConfig_pb2.pyi +6 -3
  101. streamlit/proto/NewSession_pb2.py +18 -16
  102. streamlit/proto/NewSession_pb2.pyi +158 -6
  103. streamlit/proto/PlotlyChart_pb2.py +8 -6
  104. streamlit/proto/PlotlyChart_pb2.pyi +3 -1
  105. streamlit/proto/Space_pb2.py +27 -0
  106. streamlit/proto/Space_pb2.pyi +42 -0
  107. streamlit/proto/WidgetStates_pb2.py +2 -2
  108. streamlit/proto/WidgetStates_pb2.pyi +13 -3
  109. streamlit/proto/WidthConfig_pb2.py +2 -2
  110. streamlit/proto/WidthConfig_pb2.pyi +6 -3
  111. streamlit/runtime/app_session.py +45 -6
  112. streamlit/runtime/caching/cache_data_api.py +4 -4
  113. streamlit/runtime/caching/cache_errors.py +4 -1
  114. streamlit/runtime/caching/cache_resource_api.py +3 -2
  115. streamlit/runtime/caching/cache_utils.py +2 -1
  116. streamlit/runtime/caching/cached_message_replay.py +3 -3
  117. streamlit/runtime/caching/hashing.py +3 -4
  118. streamlit/runtime/caching/legacy_cache_api.py +2 -1
  119. streamlit/runtime/connection_factory.py +1 -3
  120. streamlit/runtime/forward_msg_queue.py +4 -1
  121. streamlit/runtime/fragment.py +2 -1
  122. streamlit/runtime/memory_media_file_storage.py +1 -1
  123. streamlit/runtime/metrics_util.py +6 -2
  124. streamlit/runtime/runtime.py +14 -0
  125. streamlit/runtime/scriptrunner/exec_code.py +2 -1
  126. streamlit/runtime/scriptrunner/script_runner.py +2 -2
  127. streamlit/runtime/scriptrunner_utils/script_run_context.py +3 -6
  128. streamlit/runtime/secrets.py +2 -4
  129. streamlit/runtime/session_manager.py +3 -1
  130. streamlit/runtime/state/common.py +30 -5
  131. streamlit/runtime/state/presentation.py +85 -0
  132. streamlit/runtime/state/safe_session_state.py +2 -2
  133. streamlit/runtime/state/session_state.py +220 -16
  134. streamlit/runtime/state/widgets.py +19 -3
  135. streamlit/runtime/theme_util.py +148 -0
  136. streamlit/runtime/websocket_session_manager.py +3 -1
  137. streamlit/source_util.py +2 -2
  138. streamlit/static/index.html +2 -2
  139. streamlit/static/manifest.json +244 -227
  140. streamlit/static/static/css/{index.C8X8rNzw.css → index.BpABIXK9.css} +1 -1
  141. streamlit/static/static/css/index.DgR7E2CV.css +1 -0
  142. streamlit/static/static/js/{ErrorOutline.esm.DcGrhbBP.js → ErrorOutline.esm.YoJdlW1p.js} +1 -1
  143. streamlit/static/static/js/{FileDownload.esm.DgBvV6Pq.js → FileDownload.esm.Ddx8VEYy.js} +1 -1
  144. streamlit/static/static/js/{FileHelper.M6AAaeuA.js → FileHelper.90EtOmj9.js} +1 -1
  145. streamlit/static/static/js/{FormClearHelper.DHh1GFzm.js → FormClearHelper.BB1Km6eP.js} +1 -1
  146. streamlit/static/static/js/InputInstructions.jhH15PqV.js +1 -0
  147. streamlit/static/static/js/{Particles.DDVT-6Qc.js → Particles.DUsputn1.js} +1 -1
  148. streamlit/static/static/js/{ProgressBar.BEY0cXXV.js → ProgressBar.DLY8H6nE.js} +2 -2
  149. streamlit/static/static/js/Toolbar.D8nHCkuz.js +1 -0
  150. streamlit/static/static/js/{base-input.CK3UVGp1.js → base-input.CJGiNqed.js} +3 -3
  151. streamlit/static/static/js/{checkbox.D8W881TL.js → checkbox.Cpdd482O.js} +1 -1
  152. streamlit/static/static/js/{createSuper.B6W-Dh9S.js → createSuper.CuQIogbW.js} +1 -1
  153. streamlit/static/static/js/data-grid-overlay-editor.2Ufgxc6y.js +1 -0
  154. streamlit/static/static/js/{downloader.DiKpuU_S.js → downloader.CN0K7xlu.js} +1 -1
  155. streamlit/static/static/js/{es6.B8zRNPZ-.js → es6.BJcsVXQ0.js} +2 -2
  156. streamlit/static/static/js/{iframeResizer.contentWindow.DIewJmmh.js → iframeResizer.contentWindow.XzUvQqcZ.js} +1 -1
  157. streamlit/static/static/js/index.B1ZQh4P1.js +1 -0
  158. streamlit/static/static/js/index.BKstZk0M.js +27 -0
  159. streamlit/static/static/js/{index.Bte_9Lyq.js → index.BMcFsUee.js} +1 -1
  160. streamlit/static/static/js/{index.qhs54UAB.js → index.BR-IdcTb.js} +1 -1
  161. streamlit/static/static/js/{index.CejBxbg1.js → index.B_dWA3vd.js} +1 -1
  162. streamlit/static/static/js/{index.D5naqx-J.js → index.BgnZEMVh.js} +1 -1
  163. streamlit/static/static/js/{index.C7fRKRs4.js → index.BohqXifI.js} +1 -1
  164. streamlit/static/static/js/{index.cnnXF7xQ.js → index.Br5nxKNj.js} +1 -1
  165. streamlit/static/static/js/index.BrIKVbNc.js +3 -0
  166. streamlit/static/static/js/index.BtWUPzle.js +1 -0
  167. streamlit/static/static/js/index.C0RLraek.js +1 -0
  168. streamlit/static/static/js/{index.CP5TD2z1.js → index.CAIjskgG.js} +1 -1
  169. streamlit/static/static/js/{index.CD8HuT3N.js → index.CAj-7vWz.js} +135 -162
  170. streamlit/static/static/js/{index.DtYN2x4k.js → index.CMtEit2O.js} +1 -1
  171. streamlit/static/static/js/index.CkRlykEE.js +12 -0
  172. streamlit/static/static/js/{index.Ts_0SdB9.js → index.CmN3FXfI.js} +2 -2
  173. streamlit/static/static/js/{index.BnEpvLEz.js → index.CwbFI1_-.js} +1 -1
  174. streamlit/static/static/js/{index.CcJf6BCU.js → index.CxIUUfab.js} +27 -27
  175. streamlit/static/static/js/index.D2KPNy7e.js +1 -0
  176. streamlit/static/static/js/{index.Ch7MBCx0.js → index.D3GPA5k4.js} +47 -47
  177. streamlit/static/static/js/{index.ho6NIXGl.js → index.DGAh7DMq.js} +1 -1
  178. streamlit/static/static/js/index.DKb_NvmG.js +197 -0
  179. streamlit/static/static/js/{index.CvYYtxD_.js → index.DMqgUYKq.js} +1 -1
  180. streamlit/static/static/js/{index.zecpGxtj.js → index.DOFlg3dS.js} +1 -1
  181. streamlit/static/static/js/{index.B9mjBcgE.js → index.DPUXkcQL.js} +1 -1
  182. streamlit/static/static/js/index.DX1xY89g.js +1 -0
  183. streamlit/static/static/js/index.DYATBCsq.js +2 -0
  184. streamlit/static/static/js/{index.D2-atlaQ.js → index.DaSmGJ76.js} +3 -3
  185. streamlit/static/static/js/index.Dd7bMeLP.js +1 -0
  186. streamlit/static/static/js/{index.4eF4NxG2.js → index.DjmmgI5U.js} +1 -1
  187. streamlit/static/static/js/index.Dq56CyM2.js +1 -0
  188. streamlit/static/static/js/index.DuiXaS5_.js +7 -0
  189. streamlit/static/static/js/index.DvFidMLe.js +2 -0
  190. streamlit/static/static/js/{index.452cqrrL.js → index.DwkhC5Pc.js} +1 -1
  191. streamlit/static/static/js/{index.Dk4C7X3i.js → index.Q-3sFn1v.js} +1 -1
  192. streamlit/static/static/js/{index.CjXWwH-y.js → index.QJ5QO9sJ.js} +1 -1
  193. streamlit/static/static/js/{index.B6U8LQo3.js → index.VwTaeety.js} +1 -1
  194. streamlit/static/static/js/index.YOqQbeX8.js +1 -0
  195. streamlit/static/static/js/{input.nzVJphXi.js → input.D4MN_FzN.js} +1 -1
  196. streamlit/static/static/js/{memory.CjCgTQz3.js → memory.DrZjtdGT.js} +1 -1
  197. streamlit/static/static/js/{number-overlay-editor.DaRFzZEO.js → number-overlay-editor.DRwAw1In.js} +1 -1
  198. streamlit/static/static/js/{possibleConstructorReturn.DgiPnZ9N.js → possibleConstructorReturn.exeeJQEP.js} +1 -1
  199. streamlit/static/static/js/record.B-tDciZb.js +1 -0
  200. streamlit/static/static/js/{sandbox.mithfq7Z.js → sandbox.ClO3IuUr.js} +1 -1
  201. streamlit/static/static/js/{timepicker.Dbl5KFh6.js → timepicker.DAhu-vcF.js} +4 -4
  202. streamlit/static/static/js/{toConsumableArray.D-Dx88BQ.js → toConsumableArray.DNbljYEC.js} +1 -1
  203. streamlit/static/static/js/{uniqueId.Bh26R_3S.js → uniqueId.oG4Gvj1v.js} +1 -1
  204. streamlit/static/static/js/{useBasicWidgetState.DeK-QJpD.js → useBasicWidgetState.D6sOH6oI.js} +1 -1
  205. streamlit/static/static/js/{useTextInputAutoExpand.4iAdLWD-.js → useTextInputAutoExpand.4u3_GcuN.js} +2 -2
  206. streamlit/static/static/js/{useUpdateUiValue.CmT7_nJN.js → useUpdateUiValue.F2R3eTeR.js} +1 -1
  207. streamlit/static/static/js/wavesurfer.esm.vI8Eid4k.js +73 -0
  208. streamlit/static/static/js/withFullScreenWrapper.zothJIsI.js +1 -0
  209. streamlit/static/static/media/MaterialSymbols-Rounded.C7IFxh57.woff2 +0 -0
  210. streamlit/string_util.py +56 -1
  211. streamlit/testing/v1/app_test.py +2 -2
  212. streamlit/testing/v1/element_tree.py +23 -9
  213. streamlit/testing/v1/util.py +2 -2
  214. streamlit/type_util.py +3 -4
  215. streamlit/url_util.py +1 -3
  216. streamlit/user_info.py +1 -2
  217. streamlit/util.py +3 -1
  218. streamlit/watcher/event_based_path_watcher.py +23 -12
  219. streamlit/watcher/local_sources_watcher.py +11 -1
  220. streamlit/watcher/path_watcher.py +9 -6
  221. streamlit/watcher/polling_path_watcher.py +4 -1
  222. streamlit/watcher/util.py +2 -2
  223. streamlit/web/bootstrap.py +0 -31
  224. streamlit/web/cli.py +51 -22
  225. streamlit/web/server/bidi_component_request_handler.py +193 -0
  226. streamlit/web/server/component_file_utils.py +97 -0
  227. streamlit/web/server/component_request_handler.py +8 -21
  228. streamlit/web/server/oidc_mixin.py +3 -1
  229. streamlit/web/server/routes.py +18 -5
  230. streamlit/web/server/server.py +10 -0
  231. streamlit/web/server/server_util.py +3 -1
  232. streamlit/web/server/upload_file_request_handler.py +3 -1
  233. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/METADATA +4 -5
  234. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/RECORD +238 -209
  235. streamlit/static/static/css/index.COe1010n.css +0 -1
  236. streamlit/static/static/js/Hooks.DGu1od_L.js +0 -1
  237. streamlit/static/static/js/InputInstructions.z6sVgyYt.js +0 -1
  238. streamlit/static/static/js/Toolbar.DSnK1fUh.js +0 -1
  239. streamlit/static/static/js/data-grid-overlay-editor.DRTHOydk.js +0 -1
  240. streamlit/static/static/js/index.BXYmrqnf.js +0 -1
  241. streamlit/static/static/js/index.B_8AnktO.js +0 -1
  242. streamlit/static/static/js/index.Bl7zGQSh.js +0 -7
  243. streamlit/static/static/js/index.BnJIOYn9.js +0 -73
  244. streamlit/static/static/js/index.C1HcTl5K.js +0 -1
  245. streamlit/static/static/js/index.C7lSmSOP.js +0 -1
  246. streamlit/static/static/js/index.C_tmcx4B.js +0 -1
  247. streamlit/static/static/js/index.D3K5nOu9.js +0 -197
  248. streamlit/static/static/js/index.DkKT3LUI.js +0 -1
  249. streamlit/static/static/js/index.MTPPBDHk.js +0 -2
  250. streamlit/static/static/js/index.pqW9AMJD.js +0 -3
  251. streamlit/static/static/js/index.urHgTgMQ.js +0 -12
  252. streamlit/static/static/js/index.wzkv_11M.js +0 -1
  253. streamlit/static/static/js/index.yF5AncHY.js +0 -1
  254. streamlit/static/static/js/withFullScreenWrapper.DLp1ENGm.js +0 -1
  255. streamlit/static/static/media/MaterialSymbols-Rounded.CBxVaFdk.woff2 +0 -0
  256. {streamlit-1.49.1.data → streamlit-1.51.0.data}/scripts/streamlit.cmd +0 -0
  257. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/WHEEL +0 -0
  258. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/entry_points.txt +0 -0
  259. {streamlit-1.49.1.dist-info → streamlit-1.51.0.dist-info}/top_level.txt +0 -0
@@ -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",
@@ -316,6 +376,7 @@ class PlotlyMixin:
316
376
  "box",
317
377
  "lasso",
318
378
  ),
379
+ config: dict[str, Any] | None = None,
319
380
  **kwargs: Any,
320
381
  ) -> DeltaGenerator | PlotlyState:
321
382
  """Display an interactive Plotly chart.
@@ -356,13 +417,33 @@ class PlotlyMixin:
356
417
  render in SVG mode when passed to ``st.plotly_chart``:
357
418
  ``px.line(df, x="x", y="y", render_mode="svg")``.
358
419
 
359
- 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
360
433
  Whether to override the figure's native width with the width of
361
- the parent container. If ``use_container_width`` is ``True`` (default),
362
- Streamlit sets the width of the figure to match the width of the parent
363
- container. If ``use_container_width`` is ``False``, Streamlit sets the
364
- width of the chart to fit its contents according to the plotting library,
365
- 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"``.
366
447
 
367
448
  theme : "streamlit" or None
368
449
  The theme of the chart. If ``theme`` is ``"streamlit"`` (default),
@@ -415,6 +496,12 @@ class PlotlyMixin:
415
496
 
416
497
  All selections modes are activated by default.
417
498
 
499
+ config : dict or None
500
+ A dictionary of Plotly configuration options. This is passed to
501
+ Plotly's ``show()`` function. For more information about Plotly
502
+ configuration options, see Plotly's documentation on `Configuration
503
+ in Python <https://plotly.com/python/configuration-options/>`_.
504
+
418
505
  **kwargs
419
506
  Additional arguments accepted by Plotly's ``plot()`` function.
420
507
 
@@ -423,6 +510,10 @@ class PlotlyMixin:
423
510
  see Plotly's documentation on `Configuration in Python
424
511
  <https://plotly.com/python/configuration-options/>`_.
425
512
 
513
+ .. deprecated::
514
+ ``**kwargs`` are deprecated and will be removed in a future
515
+ release. Use ``config`` instead.
516
+
426
517
  Returns
427
518
  -------
428
519
  element or dict
@@ -486,6 +577,25 @@ class PlotlyMixin:
486
577
  height: 550px
487
578
 
488
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
+
489
599
  import plotly.io
490
600
  import plotly.tools
491
601
 
@@ -493,11 +603,11 @@ class PlotlyMixin:
493
603
  # for their main parameter. I don't like the name, but it's best to
494
604
  # keep it in sync with what Plotly calls it.
495
605
 
496
- if "sharing" in kwargs:
606
+ if kwargs:
497
607
  show_deprecation_warning(
498
- "The `sharing` parameter has been deprecated and will be removed "
499
- "in a future release. Plotly charts will always be rendered using "
500
- "Streamlit's offline mode."
608
+ "The keyword arguments have been deprecated and will be removed "
609
+ "in a future release. Use `config` instead to specify Plotly "
610
+ "configuration options."
501
611
  )
502
612
 
503
613
  if theme not in ["streamlit", None]:
@@ -538,15 +648,10 @@ class PlotlyMixin:
538
648
  )
539
649
 
540
650
  plotly_chart_proto = PlotlyChartProto()
541
- plotly_chart_proto.use_container_width = use_container_width
542
651
  plotly_chart_proto.theme = theme or ""
543
652
  plotly_chart_proto.form_id = current_form_id(self.dg)
544
653
 
545
- config = dict(kwargs.get("config", {}))
546
- # Copy over some kwargs to config dict. Plotly does the same in plot().
547
- config.setdefault("showLink", kwargs.get("show_link", False))
548
- config.setdefault("linkText", kwargs.get("link_text", False))
549
-
654
+ config = config or {}
550
655
  plotly_chart_proto.spec = plotly.io.to_json(figure, validate=False)
551
656
  plotly_chart_proto.config = json.dumps(config)
552
657
 
@@ -558,15 +663,19 @@ class PlotlyMixin:
558
663
  plotly_chart_proto.id = compute_and_register_element_id(
559
664
  "plotly_chart",
560
665
  user_key=key,
666
+ key_as_main_identity=False,
561
667
  dg=self.dg,
562
668
  plotly_spec=plotly_chart_proto.spec,
563
669
  plotly_config=plotly_chart_proto.config,
564
670
  selection_mode=selection_mode,
565
671
  is_selection_activated=is_selection_activated,
566
672
  theme=theme,
567
- use_container_width=use_container_width,
673
+ width=width,
568
674
  )
569
675
 
676
+ # Handle "content" width by inspecting the figure's natural width
677
+ final_width = _resolve_content_width(width, figure)
678
+
570
679
  if is_selection_activated:
571
680
  # Selections are activated, treat plotly chart as a widget:
572
681
  plotly_chart_proto.selection_mode.extend(
@@ -584,9 +693,16 @@ class PlotlyMixin:
584
693
  value_type="string_value",
585
694
  )
586
695
 
587
- 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
+ )
588
700
  return widget_state.value
589
- 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
+ )
590
706
 
591
707
  @property
592
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:
@@ -99,15 +99,15 @@ class PyplotMixin:
99
99
  contents according to the plotting library, up to the width of the
100
100
  parent container.
101
101
 
102
+ .. deprecated::
103
+ ``use_container_width`` is deprecated and will be removed in a
104
+ future release. For ``use_container_width=True``, use
105
+ ``width="stretch"``. For ``use_container_width=False``, use
106
+ ``width="content"``.
107
+
102
108
  **kwargs : any
103
109
  Arguments to pass to Matplotlib's savefig function.
104
110
 
105
- .. deprecated::
106
- ``use_container_width`` is deprecated and will be removed in a
107
- future release. For ``use_container_width=True``, use
108
- ``width="stretch"``. For ``use_container_width=False``, use
109
- ``width="content"``.
110
-
111
111
  Example
112
112
  -------
113
113
  >>> import matplotlib.pyplot as plt
@@ -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)