streamlit-nightly 1.34.1.dev20240513__py2.py3-none-any.whl → 1.34.1.dev20240516__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 (32) hide show
  1. streamlit/delta_generator.py +4 -4
  2. streamlit/elements/arrow.py +4 -4
  3. streamlit/elements/lib/column_config_utils.py +4 -1
  4. streamlit/elements/plotly_chart.py +4 -4
  5. streamlit/elements/vega_charts.py +410 -47
  6. streamlit/proto/ArrowVegaLiteChart_pb2.py +2 -2
  7. streamlit/proto/ArrowVegaLiteChart_pb2.pyi +15 -2
  8. streamlit/runtime/metrics_util.py +1 -1
  9. streamlit/runtime/state/common.py +3 -1
  10. streamlit/runtime/state/widgets.py +1 -0
  11. streamlit/static/asset-manifest.json +8 -10
  12. streamlit/static/index.html +1 -1
  13. streamlit/static/static/js/1168.14f7c6ff.chunk.js +1 -0
  14. streamlit/static/static/js/474.7eb0c6cd.chunk.js +1 -0
  15. streamlit/static/static/js/5345.73d26e5d.chunk.js +1 -0
  16. streamlit/static/static/js/5441.1b94928f.chunk.js +1 -0
  17. streamlit/static/static/js/8148.f80eec24.chunk.js +1 -0
  18. streamlit/static/static/js/{main.45247b52.js → main.60ba1bc7.js} +2 -2
  19. {streamlit_nightly-1.34.1.dev20240513.dist-info → streamlit_nightly-1.34.1.dev20240516.dist-info}/METADATA +1 -1
  20. {streamlit_nightly-1.34.1.dev20240513.dist-info → streamlit_nightly-1.34.1.dev20240516.dist-info}/RECORD +25 -27
  21. streamlit/static/static/js/1168.7452e363.chunk.js +0 -1
  22. streamlit/static/static/js/3631.be5c35fa.chunk.js +0 -1
  23. streamlit/static/static/js/474.87506447.chunk.js +0 -1
  24. streamlit/static/static/js/5345.65c91ee7.chunk.js +0 -1
  25. streamlit/static/static/js/5441.5bacdeda.chunk.js +0 -1
  26. streamlit/static/static/js/8148.cc5b50d8.chunk.js +0 -1
  27. streamlit/static/static/js/9758.6e6d8662.chunk.js +0 -1
  28. /streamlit/static/static/js/{main.45247b52.js.LICENSE.txt → main.60ba1bc7.js.LICENSE.txt} +0 -0
  29. {streamlit_nightly-1.34.1.dev20240513.data → streamlit_nightly-1.34.1.dev20240516.data}/scripts/streamlit.cmd +0 -0
  30. {streamlit_nightly-1.34.1.dev20240513.dist-info → streamlit_nightly-1.34.1.dev20240516.dist-info}/WHEEL +0 -0
  31. {streamlit_nightly-1.34.1.dev20240513.dist-info → streamlit_nightly-1.34.1.dev20240516.dist-info}/entry_points.txt +0 -0
  32. {streamlit_nightly-1.34.1.dev20240513.dist-info → streamlit_nightly-1.34.1.dev20240516.dist-info}/top_level.txt +0 -0
@@ -20,7 +20,20 @@ import hashlib
20
20
  import json
21
21
  import re
22
22
  from contextlib import nullcontext
23
- from typing import TYPE_CHECKING, Any, Final, Literal, Sequence, cast
23
+ from dataclasses import dataclass
24
+ from typing import (
25
+ TYPE_CHECKING,
26
+ Any,
27
+ Final,
28
+ Iterable,
29
+ Literal,
30
+ Sequence,
31
+ TypedDict,
32
+ cast,
33
+ overload,
34
+ )
35
+
36
+ from typing_extensions import TypeAlias
24
37
 
25
38
  import streamlit.elements.lib.dicttools as dicttools
26
39
  from streamlit import type_util
@@ -29,11 +42,16 @@ from streamlit.elements.lib.built_in_chart_utils import (
29
42
  ChartType,
30
43
  generate_chart,
31
44
  )
45
+ from streamlit.elements.lib.event_utils import AttributeDictionary
32
46
  from streamlit.errors import StreamlitAPIException
33
47
  from streamlit.proto.ArrowVegaLiteChart_pb2 import (
34
48
  ArrowVegaLiteChart as ArrowVegaLiteChartProto,
35
49
  )
36
50
  from streamlit.runtime.metrics_util import gather_metrics
51
+ from streamlit.runtime.scriptrunner import get_script_run_ctx
52
+ from streamlit.runtime.state import register_widget
53
+ from streamlit.runtime.state.common import compute_widget_id
54
+ from streamlit.type_util import Key, to_key
37
55
  from streamlit.util import HASHLIB_KWARGS
38
56
 
39
57
  if TYPE_CHECKING:
@@ -42,6 +60,7 @@ if TYPE_CHECKING:
42
60
  from streamlit.color_util import Color
43
61
  from streamlit.delta_generator import DeltaGenerator
44
62
  from streamlit.elements.arrow import Data
63
+ from streamlit.runtime.state import WidgetCallback
45
64
 
46
65
  # See https://vega.github.io/vega-lite/docs/encoding.html
47
66
  _CHANNELS: Final = {
@@ -73,18 +92,55 @@ _CHANNELS: Final = {
73
92
  "column",
74
93
  }
75
94
 
95
+ VegaLiteSpec: TypeAlias = "dict[str, Any]"
96
+
97
+
98
+ class VegaLiteState(TypedDict, total=False):
99
+ """
100
+ A dictionary representing the current selection state of the VegaLite chart.
101
+ Attributes
102
+ ----------
103
+ selection : AttributeDictionary
104
+ The state of the `on_select` event.
105
+ """
106
+
107
+ selection: AttributeDictionary
108
+
109
+
110
+ @dataclass
111
+ class VegaLiteStateSerde:
112
+ """VegaLiteStateSerde is used to serialize and deserialize the VegaLite Chart state."""
113
+
114
+ selection_parameters: Sequence[str]
115
+
116
+ def deserialize(self, ui_value: str | None, widget_id: str = "") -> VegaLiteState:
117
+ empty_selection_state: VegaLiteState = {
118
+ "selection": AttributeDictionary(
119
+ # Initialize the select state with empty dictionaries for each selection parameter.
120
+ {param: {} for param in self.selection_parameters}
121
+ ),
122
+ }
123
+
124
+ selection_state = (
125
+ empty_selection_state
126
+ if ui_value is None
127
+ else cast(VegaLiteState, AttributeDictionary(json.loads(ui_value)))
128
+ )
129
+
130
+ if "selection" not in selection_state:
131
+ selection_state = empty_selection_state
132
+
133
+ return cast(VegaLiteState, AttributeDictionary(selection_state))
134
+
135
+ def serialize(self, selection_state: VegaLiteState) -> str:
136
+ return json.dumps(selection_state, default=str)
137
+
76
138
 
77
139
  def _prepare_vega_lite_spec(
78
- spec: dict[str, Any] | None = None,
140
+ spec: VegaLiteSpec,
79
141
  use_container_width: bool = False,
80
142
  **kwargs,
81
- ) -> dict[str, Any]:
82
- # Support passing no spec arg, but filling it with kwargs.
83
- # Example:
84
- # marshall(proto, baz='boz')
85
- if spec is None:
86
- spec = dict()
87
-
143
+ ) -> VegaLiteSpec:
88
144
  if len(kwargs):
89
145
  # Support passing in kwargs. Example:
90
146
  # marshall(proto, {foo: 'bar'}, baz='boz')
@@ -124,7 +180,7 @@ def _serialize_data(data: Any) -> bytes:
124
180
 
125
181
  def _marshall_chart_data(
126
182
  proto: ArrowVegaLiteChartProto,
127
- spec: dict[str, Any],
183
+ spec: VegaLiteSpec,
128
184
  data: Data = None,
129
185
  ) -> None:
130
186
  """Adds the data to the proto and removes it from the spec dict.
@@ -172,7 +228,7 @@ def _marshall_chart_data(
172
228
  proto.data.data = _serialize_data(data)
173
229
 
174
230
 
175
- def _convert_altair_to_vega_lite_spec(altair_chart: alt.Chart) -> dict[str, Any]:
231
+ def _convert_altair_to_vega_lite_spec(altair_chart: alt.Chart) -> VegaLiteSpec:
176
232
  """Convert an Altair chart object to a Vega-Lite chart spec."""
177
233
  import altair as alt
178
234
 
@@ -189,7 +245,6 @@ def _convert_altair_to_vega_lite_spec(altair_chart: alt.Chart) -> dict[str, Any]
189
245
  stores the bytes into the datasets mapping and
190
246
  returns this name to have it be used in Altair.
191
247
  """
192
-
193
248
  # Already serialize the data to be able to create a stable
194
249
  # dataset name:
195
250
  data_bytes = _serialize_data(data)
@@ -215,6 +270,97 @@ def _convert_altair_to_vega_lite_spec(altair_chart: alt.Chart) -> dict[str, Any]
215
270
  return chart_dict
216
271
 
217
272
 
273
+ def _disallow_multi_view_charts(spec: VegaLiteSpec) -> None:
274
+ """Raise an exception if the spec contains a multi-view chart (view composition).
275
+
276
+ This is intended to be used as a temporary solution to prevent selections on
277
+ multi-view charts. There are too many edge cases to handle selections on these
278
+ charts correctly, so we're disallowing them for now.
279
+
280
+ More information about view compositions: https://vega.github.io/vega-lite/docs/composition.html
281
+ """
282
+
283
+ if (
284
+ any(key in spec for key in ["layer", "hconcat", "vconcat", "concat", "spec"])
285
+ or "encoding" not in spec
286
+ ):
287
+ raise StreamlitAPIException(
288
+ "Selections are not yet supported for multi-view charts (chart compositions). "
289
+ "If you would like to use selections on multi-view charts, please upvote "
290
+ "this [Github issue](https://github.com/streamlit/streamlit/issues/8643)."
291
+ )
292
+
293
+
294
+ def _extract_selection_parameters(spec: VegaLiteSpec) -> set[str]:
295
+ """Extract the names of all valid selection parameters from the spec."""
296
+ if not spec or "params" not in spec:
297
+ return set()
298
+
299
+ param_names = set()
300
+
301
+ for param in spec["params"]:
302
+ # Check if it looks like a valid selection parameter:
303
+ # https://vega.github.io/vega-lite/docs/selection.html
304
+ if param.get("name") and param.get("select"):
305
+ # Selection found, just return here to not show the exception.
306
+ param_names.add(param["name"])
307
+
308
+ return param_names
309
+
310
+
311
+ def _parse_selection_mode(
312
+ spec: VegaLiteSpec,
313
+ selection_mode: str | Iterable[str] | None,
314
+ ) -> list[str]:
315
+ """Parse and check the user provided selection modes.
316
+
317
+ This will raise an exception if no valid selection parameters are found in the spec
318
+ or if the user provided selection modes are not defined in the spec.
319
+
320
+ Parameters
321
+ ----------
322
+ spec : VegaLiteSpec
323
+ The Vega-Lite chart specification.
324
+
325
+ selection_mode : str, Iterable[str], or None
326
+ The user provided selection mode(s).
327
+
328
+ Returns
329
+ -------
330
+ list[str]
331
+ The parsed selection mode(s) that should be activated.
332
+ """
333
+
334
+ # Extract all selection parameters from the spec:
335
+ all_selection_params = _extract_selection_parameters(spec)
336
+
337
+ if not all_selection_params:
338
+ raise StreamlitAPIException(
339
+ "Selections are activated, but the provided chart spec does not "
340
+ "have any selections defined. To add selections to `st.altair_chart`, check out the documentation "
341
+ "[here](https://altair-viz.github.io/user_guide/interactions.html#selections-capturing-chart-interactions). "
342
+ "For adding selections to `st.vega_lite_chart`, take a look "
343
+ "at the specification [here](https://vega.github.io/vega-lite/docs/selection.html)."
344
+ )
345
+
346
+ if selection_mode is None:
347
+ # Activate all selection parameters:
348
+ return sorted(list(all_selection_params))
349
+
350
+ if isinstance(selection_mode, str):
351
+ # Convert single string to list:
352
+ selection_mode = [selection_mode]
353
+
354
+ # Check that all provided selection parameters are defined in the spec:
355
+ for selection_name in selection_mode:
356
+ if selection_name not in all_selection_params:
357
+ raise StreamlitAPIException(
358
+ f"Selection parameter '{selection_name}' is not defined in the chart spec. "
359
+ f"Available selection parameters are: {all_selection_params}."
360
+ )
361
+ return sorted(list(selection_mode))
362
+
363
+
218
364
  def _reset_counter_pattern(prefix: str, vega_spec: str) -> str:
219
365
  """Altair uses a global counter for unnamed parameters and views.
220
366
  We need to reset these counters on a spec-level to make the
@@ -459,11 +605,14 @@ class VegaChartsMixin:
459
605
  width=width,
460
606
  height=height,
461
607
  )
462
- return self._altair_chart(
463
- chart,
464
- use_container_width=use_container_width,
465
- theme="streamlit",
466
- add_rows_metadata=add_rows_metadata,
608
+ return cast(
609
+ "DeltaGenerator",
610
+ self._altair_chart(
611
+ chart,
612
+ use_container_width=use_container_width,
613
+ theme="streamlit",
614
+ add_rows_metadata=add_rows_metadata,
615
+ ),
467
616
  )
468
617
 
469
618
  @gather_metrics("area_chart")
@@ -618,11 +767,14 @@ class VegaChartsMixin:
618
767
  width=width,
619
768
  height=height,
620
769
  )
621
- return self._altair_chart(
622
- chart,
623
- use_container_width=use_container_width,
624
- theme="streamlit",
625
- add_rows_metadata=add_rows_metadata,
770
+ return cast(
771
+ "DeltaGenerator",
772
+ self._altair_chart(
773
+ chart,
774
+ use_container_width=use_container_width,
775
+ theme="streamlit",
776
+ add_rows_metadata=add_rows_metadata,
777
+ ),
626
778
  )
627
779
 
628
780
  @gather_metrics("bar_chart")
@@ -779,11 +931,14 @@ class VegaChartsMixin:
779
931
  width=width,
780
932
  height=height,
781
933
  )
782
- return self._altair_chart(
783
- chart,
784
- use_container_width=use_container_width,
785
- theme="streamlit",
786
- add_rows_metadata=add_rows_metadata,
934
+ return cast(
935
+ "DeltaGenerator",
936
+ self._altair_chart(
937
+ chart,
938
+ use_container_width=use_container_width,
939
+ theme="streamlit",
940
+ add_rows_metadata=add_rows_metadata,
941
+ ),
787
942
  )
788
943
 
789
944
  @gather_metrics("scatter_chart")
@@ -953,20 +1108,53 @@ class VegaChartsMixin:
953
1108
  width=width,
954
1109
  height=height,
955
1110
  )
956
- return self._altair_chart(
957
- chart,
958
- use_container_width=use_container_width,
959
- theme="streamlit",
960
- add_rows_metadata=add_rows_metadata,
1111
+ return cast(
1112
+ "DeltaGenerator",
1113
+ self._altair_chart(
1114
+ chart,
1115
+ use_container_width=use_container_width,
1116
+ theme="streamlit",
1117
+ add_rows_metadata=add_rows_metadata,
1118
+ ),
961
1119
  )
962
1120
 
963
- @gather_metrics("altair_chart")
1121
+ @overload
964
1122
  def altair_chart(
965
1123
  self,
966
1124
  altair_chart: alt.Chart,
1125
+ *,
967
1126
  use_container_width: bool = False,
968
1127
  theme: Literal["streamlit"] | None = "streamlit",
1128
+ key: Key | None = None,
1129
+ on_select: Literal["ignore"], # No default value here to make it work with mypy
1130
+ selection_mode: str | Iterable[str] | None = None,
969
1131
  ) -> DeltaGenerator:
1132
+ ...
1133
+
1134
+ @overload
1135
+ def altair_chart(
1136
+ self,
1137
+ altair_chart: alt.Chart,
1138
+ *,
1139
+ use_container_width: bool = False,
1140
+ theme: Literal["streamlit"] | None = "streamlit",
1141
+ key: Key | None = None,
1142
+ on_select: Literal["rerun"] | WidgetCallback = "rerun",
1143
+ selection_mode: str | Iterable[str] | None = None,
1144
+ ) -> VegaLiteState:
1145
+ ...
1146
+
1147
+ @gather_metrics("altair_chart")
1148
+ def altair_chart(
1149
+ self,
1150
+ altair_chart: alt.Chart,
1151
+ *,
1152
+ use_container_width: bool = False,
1153
+ theme: Literal["streamlit"] | None = "streamlit",
1154
+ key: Key | None = None,
1155
+ on_select: Literal["rerun", "ignore"] | WidgetCallback = "ignore",
1156
+ selection_mode: str | Iterable[str] | None = None,
1157
+ ) -> DeltaGenerator | VegaLiteState:
970
1158
  """Display a chart using the Altair library.
971
1159
 
972
1160
  Parameters
@@ -982,6 +1170,20 @@ class VegaChartsMixin:
982
1170
  The theme of the chart. Currently, we only support "streamlit" for the Streamlit
983
1171
  defined design or None to fallback to the default behavior of the library.
984
1172
 
1173
+ key : str
1174
+ An optional string to use as the unique key for this element when used in combination
1175
+ with ```on_select```. If this is omitted, a key will be generated for the widget based
1176
+ on its content. Multiple widgets of the same type may not share the same key.
1177
+
1178
+ on_select : "ignore" or "rerun" or callable
1179
+ Controls the behavior in response to selection events on the charts. Can be one of:
1180
+ - "ignore" (default): Streamlit will not react to any selection events in the chart.
1181
+ - "rerun: Streamlit will rerun the app when the user selects data in the chart. In this case,
1182
+ ```st.altair_chart``` will return the selection data as a dictionary.
1183
+ - callable: If a callable is provided, Streamlit will rerun and execute the callable as a
1184
+ callback function before the rest of the app. The selection data can be retrieved through
1185
+ session state by setting the key parameter.
1186
+
985
1187
  Example
986
1188
  -------
987
1189
 
@@ -1009,18 +1211,57 @@ class VegaChartsMixin:
1009
1211
 
1010
1212
  """
1011
1213
  return self._altair_chart(
1012
- altair_chart, use_container_width=use_container_width, theme=theme
1214
+ altair_chart=altair_chart,
1215
+ use_container_width=use_container_width,
1216
+ theme=theme,
1217
+ key=key,
1218
+ on_select=on_select,
1219
+ selection_mode=selection_mode,
1013
1220
  )
1014
1221
 
1015
- @gather_metrics("vega_lite_chart")
1222
+ @overload
1016
1223
  def vega_lite_chart(
1017
1224
  self,
1018
1225
  data: Data = None,
1019
- spec: dict[str, Any] | None = None,
1226
+ spec: VegaLiteSpec | None = None,
1227
+ *,
1020
1228
  use_container_width: bool = False,
1021
1229
  theme: Literal["streamlit"] | None = "streamlit",
1230
+ key: Key | None = None,
1231
+ on_select: Literal["ignore"], # No default value here to make it work with mypy
1232
+ selection_mode: str | Iterable[str] | None = None,
1022
1233
  **kwargs: Any,
1023
1234
  ) -> DeltaGenerator:
1235
+ ...
1236
+
1237
+ @overload
1238
+ def vega_lite_chart(
1239
+ self,
1240
+ data: Data = None,
1241
+ spec: VegaLiteSpec | None = None,
1242
+ *,
1243
+ use_container_width: bool = False,
1244
+ theme: Literal["streamlit"] | None = "streamlit",
1245
+ key: Key | None = None,
1246
+ on_select: Literal["rerun"] | WidgetCallback = "rerun",
1247
+ selection_mode: str | Iterable[str] | None = None,
1248
+ **kwargs: Any,
1249
+ ) -> VegaLiteState:
1250
+ ...
1251
+
1252
+ @gather_metrics("vega_lite_chart")
1253
+ def vega_lite_chart(
1254
+ self,
1255
+ data: Data = None,
1256
+ spec: VegaLiteSpec | None = None,
1257
+ *,
1258
+ use_container_width: bool = False,
1259
+ theme: Literal["streamlit"] | None = "streamlit",
1260
+ key: Key | None = None,
1261
+ on_select: Literal["rerun", "ignore"] | WidgetCallback = "ignore",
1262
+ selection_mode: str | Iterable[str] | None = None,
1263
+ **kwargs: Any,
1264
+ ) -> DeltaGenerator | VegaLiteState:
1024
1265
  """Display a chart using the Vega-Lite library.
1025
1266
 
1026
1267
  Parameters
@@ -1042,6 +1283,20 @@ class VegaChartsMixin:
1042
1283
  The theme of the chart. Currently, we only support "streamlit" for the Streamlit
1043
1284
  defined design or None to fallback to the default behavior of the library.
1044
1285
 
1286
+ key : str
1287
+ An optional string to use as the unique key for this element when used in combination
1288
+ with ```on_select```. If this is omitted, a key will be generated for the widget based
1289
+ on its content. Multiple widgets of the same type may not share the same key.
1290
+
1291
+ on_select : "ignore" or "rerun" or callable
1292
+ Controls the behavior in response to selection events on the charts. Can be one of:
1293
+ - "ignore" (default): Streamlit will not react to any selection events in the chart.
1294
+ - "rerun: Streamlit will rerun the app when the user selects data in the chart. In this case,
1295
+ ```st.vega_lite_chart``` will return the selection data as a dictionary.
1296
+ - callable: If a callable is provided, Streamlit will rerun and execute the callable as a
1297
+ callback function before the rest of the app. The selection data can be retrieved through
1298
+ session state by setting the key parameter.
1299
+
1045
1300
  **kwargs : any
1046
1301
  Same as spec, but as keywords.
1047
1302
 
@@ -1080,6 +1335,9 @@ class VegaChartsMixin:
1080
1335
  spec=spec,
1081
1336
  use_container_width=use_container_width,
1082
1337
  theme=theme,
1338
+ key=key,
1339
+ on_select=on_select,
1340
+ selection_mode=selection_mode,
1083
1341
  **kwargs,
1084
1342
  )
1085
1343
 
@@ -1088,52 +1346,157 @@ class VegaChartsMixin:
1088
1346
  altair_chart: alt.Chart,
1089
1347
  use_container_width: bool = False,
1090
1348
  theme: Literal["streamlit"] | None = "streamlit",
1349
+ key: Key | None = None,
1350
+ on_select: Literal["rerun", "ignore"] | WidgetCallback = "ignore",
1351
+ selection_mode: str | Iterable[str] | None = None,
1091
1352
  add_rows_metadata: AddRowsMetadata | None = None,
1092
- ) -> DeltaGenerator:
1093
- """Internal method to enqueue a vega-lite chart element based on an Altair chart."""
1353
+ ) -> DeltaGenerator | VegaLiteState:
1354
+ """Internal method to enqueue a vega-lite chart element based on an Altair chart.
1355
+
1356
+ See the `altair_chart` method docstring for more information.
1357
+ """
1358
+
1359
+ if type_util.is_altair_version_less_than("5.0.0") and on_select != "ignore":
1360
+ raise StreamlitAPIException(
1361
+ "Streamlit does not support selections with Altair 4.x. Please upgrade to Version 5. "
1362
+ "If you would like to use Altair 4.x with selections, please upvote "
1363
+ "this [Github issue](https://github.com/streamlit/streamlit/issues/8516)."
1364
+ )
1365
+
1094
1366
  vega_lite_spec = _convert_altair_to_vega_lite_spec(altair_chart)
1095
1367
  return self._vega_lite_chart(
1096
1368
  data=None, # The data is already part of the spec
1097
1369
  spec=vega_lite_spec,
1098
1370
  use_container_width=use_container_width,
1099
1371
  theme=theme,
1372
+ key=key,
1373
+ on_select=on_select,
1374
+ selection_mode=selection_mode,
1100
1375
  add_rows_metadata=add_rows_metadata,
1101
1376
  )
1102
1377
 
1103
1378
  def _vega_lite_chart(
1104
1379
  self,
1105
1380
  data: Data = None,
1106
- spec: dict[str, Any] | None = None,
1381
+ spec: VegaLiteSpec | None = None,
1107
1382
  use_container_width: bool = False,
1108
1383
  theme: Literal["streamlit"] | None = "streamlit",
1384
+ key: Key | None = None,
1385
+ on_select: Literal["rerun", "ignore"] | WidgetCallback = "ignore",
1386
+ selection_mode: str | Iterable[str] | None = None,
1109
1387
  add_rows_metadata: AddRowsMetadata | None = None,
1110
1388
  **kwargs: Any,
1111
- ) -> DeltaGenerator:
1112
- """Internal method to enqueue a vega-lite chart element based on a vega-lite spec."""
1389
+ ) -> DeltaGenerator | VegaLiteState:
1390
+ """Internal method to enqueue a vega-lite chart element based on a vega-lite spec.
1391
+
1392
+ See the `vega_lite_chart` method docstring for more information.
1393
+ """
1113
1394
 
1114
1395
  if theme not in ["streamlit", None]:
1115
1396
  raise StreamlitAPIException(
1116
1397
  f'You set theme="{theme}" while Streamlit charts only support theme=”streamlit” or theme=None to fallback to the default library theme.'
1117
1398
  )
1118
1399
 
1400
+ if on_select not in ["ignore", "rerun"] and not callable(on_select):
1401
+ raise StreamlitAPIException(
1402
+ f"You have passed {on_select} to `on_select`. But only 'ignore', 'rerun', or a callable is supported."
1403
+ )
1404
+
1405
+ key = to_key(key)
1406
+ is_selection_activated = on_select != "ignore"
1407
+
1408
+ if is_selection_activated:
1409
+ # Run some checks that are only relevant when selections are activated
1410
+
1411
+ # Import here to avoid circular imports
1412
+ from streamlit.elements.utils import (
1413
+ check_cache_replay_rules,
1414
+ check_callback_rules,
1415
+ check_session_state_rules,
1416
+ )
1417
+
1418
+ check_cache_replay_rules()
1419
+ if callable(on_select):
1420
+ check_callback_rules(self.dg, on_select)
1421
+ check_session_state_rules(default_value=None, key=key, writes_allowed=False)
1422
+
1119
1423
  # Support passing data inside spec['datasets'] and spec['data'].
1120
1424
  # (The data gets pulled out of the spec dict later on.)
1121
1425
  if isinstance(data, dict) and spec is None:
1122
1426
  spec = data
1123
1427
  data = None
1124
1428
 
1125
- proto = ArrowVegaLiteChartProto()
1429
+ if spec is None:
1430
+ spec = {}
1431
+
1432
+ vega_lite_proto = ArrowVegaLiteChartProto()
1126
1433
 
1127
1434
  spec = _prepare_vega_lite_spec(spec, use_container_width, **kwargs)
1128
- _marshall_chart_data(proto, spec, data)
1435
+ _marshall_chart_data(vega_lite_proto, spec, data)
1129
1436
 
1130
1437
  # Prevent the spec from changing across reruns:
1131
- proto.spec = _stabilize_vega_json_spec(json.dumps(spec))
1132
- proto.use_container_width = use_container_width
1133
- proto.theme = theme or ""
1438
+ vega_lite_proto.spec = _stabilize_vega_json_spec(json.dumps(spec))
1439
+ vega_lite_proto.use_container_width = use_container_width
1440
+ vega_lite_proto.theme = theme or ""
1441
+
1442
+ if is_selection_activated:
1443
+ # Import here to avoid circular imports
1444
+ from streamlit.elements.form import current_form_id
1445
+
1446
+ # Load the stabilized spec again as a dict:
1447
+ final_spec = json.loads(vega_lite_proto.spec)
1448
+ # Temporary limitation to disallow multi-view charts (compositions) with selections.
1449
+ _disallow_multi_view_charts(final_spec)
1450
+
1451
+ # Parse and check the specified selection modes
1452
+ parsed_selection_modes = _parse_selection_mode(final_spec, selection_mode)
1453
+ vega_lite_proto.selection_mode.extend(parsed_selection_modes)
1454
+
1455
+ vega_lite_proto.form_id = current_form_id(self.dg)
1456
+
1457
+ ctx = get_script_run_ctx()
1458
+ vega_lite_proto.id = compute_widget_id(
1459
+ "arrow_vega_lite_chart",
1460
+ user_key=key,
1461
+ key=key,
1462
+ vega_lite_spec=vega_lite_proto.spec,
1463
+ # The data is either in vega_lite_proto.data.data
1464
+ # or in a named dataset in vega_lite_proto.datasets
1465
+ vega_lite_data=vega_lite_proto.data.data,
1466
+ # Its enough to just use the names here since they are expected
1467
+ # to contain hashes based on the dataset data.
1468
+ named_datasets=[dataset.name for dataset in vega_lite_proto.datasets],
1469
+ theme=theme,
1470
+ use_container_width=use_container_width,
1471
+ selection_mode=parsed_selection_modes,
1472
+ form_id=vega_lite_proto.form_id,
1473
+ page=ctx.page_script_hash if ctx else None,
1474
+ )
1134
1475
 
1476
+ serde = VegaLiteStateSerde(parsed_selection_modes)
1477
+
1478
+ widget_state = register_widget(
1479
+ "vega_lite_chart",
1480
+ vega_lite_proto,
1481
+ user_key=key,
1482
+ on_change_handler=on_select if callable(on_select) else None,
1483
+ deserializer=serde.deserialize,
1484
+ serializer=serde.serialize,
1485
+ ctx=ctx,
1486
+ )
1487
+
1488
+ self.dg._enqueue(
1489
+ "arrow_vega_lite_chart",
1490
+ vega_lite_proto,
1491
+ add_rows_metadata=add_rows_metadata,
1492
+ )
1493
+ return cast(VegaLiteState, widget_state.value)
1494
+ # If its not used with selections activated, just return
1495
+ # the delta generator related to this element.
1135
1496
  return self.dg._enqueue(
1136
- "arrow_vega_lite_chart", proto, add_rows_metadata=add_rows_metadata
1497
+ "arrow_vega_lite_chart",
1498
+ vega_lite_proto,
1499
+ add_rows_metadata=add_rows_metadata,
1137
1500
  )
1138
1501
 
1139
1502
  @property
@@ -15,7 +15,7 @@ from streamlit.proto import Arrow_pb2 as streamlit_dot_proto_dot_Arrow__pb2
15
15
  from streamlit.proto import ArrowNamedDataSet_pb2 as streamlit_dot_proto_dot_ArrowNamedDataSet__pb2
16
16
 
17
17
 
18
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n(streamlit/proto/ArrowVegaLiteChart.proto\x1a\x1bstreamlit/proto/Arrow.proto\x1a\'streamlit/proto/ArrowNamedDataSet.proto\"\x90\x01\n\x12\x41rrowVegaLiteChart\x12\x0c\n\x04spec\x18\x01 \x01(\t\x12\x14\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x06.Arrow\x12$\n\x08\x64\x61tasets\x18\x04 \x03(\x0b\x32\x12.ArrowNamedDataSet\x12\x1b\n\x13use_container_width\x18\x05 \x01(\x08\x12\r\n\x05theme\x18\x06 \x01(\tJ\x04\x08\x03\x10\x04\x42\x37\n\x1c\x63om.snowflake.apps.streamlitB\x17\x41rrowVegaLiteChartProtob\x06proto3')
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n(streamlit/proto/ArrowVegaLiteChart.proto\x1a\x1bstreamlit/proto/Arrow.proto\x1a\'streamlit/proto/ArrowNamedDataSet.proto\"\xc5\x01\n\x12\x41rrowVegaLiteChart\x12\x0c\n\x04spec\x18\x01 \x01(\t\x12\x14\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x06.Arrow\x12$\n\x08\x64\x61tasets\x18\x04 \x03(\x0b\x32\x12.ArrowNamedDataSet\x12\x1b\n\x13use_container_width\x18\x05 \x01(\x08\x12\r\n\x05theme\x18\x06 \x01(\t\x12\n\n\x02id\x18\x07 \x01(\t\x12\x16\n\x0eselection_mode\x18\x08 \x03(\t\x12\x0f\n\x07\x66orm_id\x18\t \x01(\tJ\x04\x08\x03\x10\x04\x42\x37\n\x1c\x63om.snowflake.apps.streamlitB\x17\x41rrowVegaLiteChartProtob\x06proto3')
19
19
 
20
20
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
21
21
  _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'streamlit.proto.ArrowVegaLiteChart_pb2', globals())
@@ -24,5 +24,5 @@ if _descriptor._USE_C_DESCRIPTORS == False:
24
24
  DESCRIPTOR._options = None
25
25
  DESCRIPTOR._serialized_options = b'\n\034com.snowflake.apps.streamlitB\027ArrowVegaLiteChartProto'
26
26
  _ARROWVEGALITECHART._serialized_start=115
27
- _ARROWVEGALITECHART._serialized_end=259
27
+ _ARROWVEGALITECHART._serialized_end=312
28
28
  # @@protoc_insertion_point(module_scope)