streamlit-nightly 1.36.1.dev20240626__py2.py3-none-any.whl → 1.36.1.dev20240627__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.
@@ -45,7 +45,7 @@ if TYPE_CHECKING:
45
45
  import pandas as pd
46
46
 
47
47
  from streamlit.elements.arrow import Data
48
- from streamlit.type_util import DataFrameCompatible
48
+ from streamlit.type_util import ChartStackType, DataFrameCompatible
49
49
 
50
50
 
51
51
  class PrepDataColumns(TypedDict):
@@ -123,6 +123,8 @@ def generate_chart(
123
123
  size_from_user: str | float | None = None,
124
124
  width: int | None = None,
125
125
  height: int | None = None,
126
+ # Bar charts only:
127
+ stack: bool | ChartStackType | None = None,
126
128
  ) -> tuple[alt.Chart, AddRowsMetadata]:
127
129
  """Function to use the chart's type, data columns and indices to figure out the chart's spec."""
128
130
  import altair as alt
@@ -166,21 +168,18 @@ def generate_chart(
166
168
 
167
169
  # At this point, x_column is only None if user did not provide one AND df is empty.
168
170
 
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
- )
171
+ # Get x and y encodings
172
+ x_encoding, y_encoding = _get_axis_encodings(
173
+ df,
174
+ chart_type,
175
+ x_column,
176
+ y_column,
177
+ x_from_user,
178
+ y_from_user,
179
+ x_axis_label,
180
+ y_axis_label,
181
+ stack,
182
+ )
184
183
 
185
184
  # Create a Chart with x and y encodings.
186
185
  chart = alt.Chart(
@@ -193,8 +192,21 @@ def generate_chart(
193
192
  y=y_encoding,
194
193
  )
195
194
 
195
+ # Offset encoding only works for Altair >= 5.0.0
196
+ is_altair_version_offset_compatible = not type_util.is_altair_version_less_than(
197
+ "5.0.0"
198
+ )
199
+ # Set up offset encoding (creates grouped/non-stacked bar charts, so only applicable when stack=False).
200
+ if (
201
+ is_altair_version_offset_compatible
202
+ and stack is False
203
+ and color_column is not None
204
+ ):
205
+ x_offset, y_offset = _get_offset_encoding(chart_type, color_column)
206
+ chart = chart.encode(xOffset=x_offset, yOffset=y_offset)
207
+
196
208
  # Set up opacity encoding.
197
- opacity_enc = _get_opacity_encoding(chart_type, color_column)
209
+ opacity_enc = _get_opacity_encoding(chart_type, stack, color_column)
198
210
  if opacity_enc is not None:
199
211
  chart = chart.encode(opacity=opacity_enc)
200
212
 
@@ -484,7 +496,7 @@ def _maybe_convert_color_column_in_place(df: pd.DataFrame, color_column: str | N
484
496
  pass
485
497
  elif is_color_tuple_like(first_color_datum):
486
498
  # Tuples need to be converted to CSS-valid.
487
- df[color_column] = df[color_column].map(to_css_color)
499
+ df.loc[:, color_column] = df[color_column].map(to_css_color)
488
500
  else:
489
501
  # Other kinds of colors columns (i.e. pure numbers or nominal strings) shouldn't
490
502
  # be converted since they are treated by Vega-Lite as sequential or categorical colors.
@@ -577,14 +589,38 @@ def _parse_y_columns(
577
589
  return y_column_list
578
590
 
579
591
 
592
+ def _get_offset_encoding(
593
+ chart_type: ChartType,
594
+ color_column: str | None,
595
+ ) -> tuple[alt.XOffset, alt.YOffset]:
596
+ # Vega's Offset encoding channel is used to create grouped/non-stacked bar charts
597
+ import altair as alt
598
+
599
+ x_offset = alt.XOffset()
600
+ y_offset = alt.YOffset()
601
+
602
+ if chart_type is ChartType.VERTICAL_BAR:
603
+ x_offset = alt.XOffset(field=color_column)
604
+ elif chart_type is ChartType.HORIZONTAL_BAR:
605
+ y_offset = alt.YOffset(field=color_column)
606
+
607
+ return x_offset, y_offset
608
+
609
+
580
610
  def _get_opacity_encoding(
581
- chart_type: ChartType, color_column: str | None
611
+ chart_type: ChartType,
612
+ stack: bool | ChartStackType | None,
613
+ color_column: str | None,
582
614
  ) -> alt.OpacityValue | None:
583
615
  import altair as alt
584
616
 
585
617
  if color_column and chart_type == ChartType.AREA:
586
618
  return alt.OpacityValue(0.7)
587
619
 
620
+ # Layered bar chart
621
+ if color_column and stack == "layered":
622
+ return alt.OpacityValue(0.7)
623
+
588
624
  return None
589
625
 
590
626
 
@@ -634,6 +670,42 @@ def _maybe_melt(
634
670
  return df, y_column, color_column
635
671
 
636
672
 
673
+ def _get_axis_encodings(
674
+ df: pd.DataFrame,
675
+ chart_type: ChartType,
676
+ x_column: str | None,
677
+ y_column: str | None,
678
+ x_from_user: str | None,
679
+ y_from_user: str | Sequence[str] | None,
680
+ x_axis_label: str | None,
681
+ y_axis_label: str | None,
682
+ stack: bool | ChartStackType | None,
683
+ ) -> tuple[alt.X, alt.Y]:
684
+ stack_encoding: alt.X | alt.Y
685
+ if chart_type == ChartType.HORIZONTAL_BAR:
686
+ # Handle horizontal bar chart - switches x and y data:
687
+ x_encoding = _get_x_encoding(
688
+ df, y_column, y_from_user, x_axis_label, chart_type
689
+ )
690
+ y_encoding = _get_y_encoding(
691
+ df, x_column, x_from_user, y_axis_label, chart_type
692
+ )
693
+ stack_encoding = x_encoding
694
+ else:
695
+ x_encoding = _get_x_encoding(
696
+ df, x_column, x_from_user, x_axis_label, chart_type
697
+ )
698
+ y_encoding = _get_y_encoding(
699
+ df, y_column, y_from_user, y_axis_label, chart_type
700
+ )
701
+ stack_encoding = y_encoding
702
+
703
+ # Handle stacking - only relevant for bar charts
704
+ _update_encoding_with_stack(stack, stack_encoding)
705
+
706
+ return x_encoding, y_encoding
707
+
708
+
637
709
  def _get_x_encoding(
638
710
  df: pd.DataFrame,
639
711
  x_column: str | None,
@@ -730,6 +802,19 @@ def _get_y_encoding(
730
802
  )
731
803
 
732
804
 
805
+ def _update_encoding_with_stack(
806
+ stack: bool | ChartStackType | None,
807
+ encoding: alt.X | alt.Y,
808
+ ) -> None:
809
+ if stack is None:
810
+ return None
811
+ # Our layered option maps to vega's stack=False option
812
+ elif stack == "layered":
813
+ stack = False
814
+
815
+ encoding["stack"] = stack
816
+
817
+
733
818
  def _get_color_encoding(
734
819
  df: pd.DataFrame,
735
820
  color_value: Color | None,
@@ -57,7 +57,7 @@ from streamlit.runtime.metrics_util import gather_metrics
57
57
  from streamlit.runtime.scriptrunner import get_script_run_ctx
58
58
  from streamlit.runtime.state import register_widget
59
59
  from streamlit.runtime.state.common import compute_widget_id
60
- from streamlit.type_util import Key, to_key
60
+ from streamlit.type_util import ChartStackType, Key, to_key
61
61
  from streamlit.util import HASHLIB_KWARGS
62
62
 
63
63
  if TYPE_CHECKING:
@@ -957,6 +957,7 @@ class VegaChartsMixin:
957
957
  y_label: str | None = None,
958
958
  color: str | Color | list[Color] | None = None,
959
959
  horizontal: bool = False,
960
+ stack: bool | ChartStackType | None = None,
960
961
  width: int | None = None,
961
962
  height: int | None = None,
962
963
  use_container_width: bool = True,
@@ -1046,6 +1047,14 @@ class VegaChartsMixin:
1046
1047
  Streamlit swaps the x-axis and y-axis and the bars display
1047
1048
  horizontally.
1048
1049
 
1050
+ stack : bool, "normalize", "center", "layered", or None
1051
+ Whether to stack the bars. If this is ``None`` (default), uses Vega's
1052
+ default. If this is ``True``, the bars are stacked on top of each other.
1053
+ If this is ``False``, the bars are displayed side by side. If "normalize",
1054
+ the bars are stacked and normalized to 100%. If "center", the bars are
1055
+ stacked around a central axis. If "layered", the bars are stacked on top
1056
+ of one another.
1057
+
1049
1058
  width : int or None
1050
1059
  Desired width of the chart expressed in pixels. If ``width`` is
1051
1060
  ``None`` (default), Streamlit sets the width of the chart to fit
@@ -1139,6 +1148,20 @@ class VegaChartsMixin:
1139
1148
 
1140
1149
  """
1141
1150
 
1151
+ # Offset encodings (used for non-stacked/grouped bar charts) are not supported in Altair < 5.0.0
1152
+ if type_util.is_altair_version_less_than("5.0.0") and stack is False:
1153
+ raise StreamlitAPIException(
1154
+ "Streamlit does not support non-stacked (grouped) bar charts with Altair 4.x. Please upgrade to Version 5."
1155
+ )
1156
+
1157
+ # Check that the stack parameter is valid, raise more informative error message if not
1158
+ VALID_STACK_TYPES = (None, True, False, "normalize", "center", "layered")
1159
+ if stack not in VALID_STACK_TYPES:
1160
+ raise StreamlitAPIException(
1161
+ f'Invalid value for stack parameter: {stack}. Stack must be one of True, False, "normalize", "center", "layered" or None. '
1162
+ "See documentation for `st.bar_chart` [here](https://docs.streamlit.io/develop/api-reference/charts/st.bar_chart) for more information."
1163
+ )
1164
+
1142
1165
  bar_chart_type = (
1143
1166
  ChartType.HORIZONTAL_BAR if horizontal else ChartType.VERTICAL_BAR
1144
1167
  )
@@ -1154,6 +1177,7 @@ class VegaChartsMixin:
1154
1177
  size_from_user=None,
1155
1178
  width=width,
1156
1179
  height=height,
1180
+ stack=stack,
1157
1181
  )
1158
1182
  return cast(
1159
1183
  "DeltaGenerator",
streamlit/type_util.py CHANGED
@@ -142,6 +142,8 @@ LabelVisibility = Literal["visible", "hidden", "collapsed"]
142
142
 
143
143
  VegaLiteType = Literal["quantitative", "ordinal", "temporal", "nominal"]
144
144
 
145
+ ChartStackType = Literal["normalize", "center", "layered"]
146
+
145
147
 
146
148
  class SupportsStr(Protocol):
147
149
  def __str__(self) -> str: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: streamlit-nightly
3
- Version: 1.36.1.dev20240626
3
+ Version: 1.36.1.dev20240627
4
4
  Summary: A faster way to build and share data apps
5
5
  Home-page: https://streamlit.io
6
6
  Author: Snowflake Inc
@@ -31,7 +31,7 @@ streamlit/source_util.py,sha256=2KOVrEhBATVh9M_bnbg9OwWPORg1riCB63JzE7g8oK0,6145
31
31
  streamlit/string_util.py,sha256=x1ZuLlorPMNUpOZYMAN1VLdxViJwfPcXQ99PKRn0pyg,6347
32
32
  streamlit/temporary_directory.py,sha256=eBv5q0CR9GApa-itZBaGtqQKMl248H0HojEVKzkS9cc,1627
33
33
  streamlit/time_util.py,sha256=zPDirzZDAOPzGogHy-4wOalfBb7zCNCvFEfkZf03otc,2836
34
- streamlit/type_util.py,sha256=0sRlyamlv31HzIt0aaOccpd1U9dtB4ghaFoVgV4gKZc,48505
34
+ streamlit/type_util.py,sha256=GEjqe0irGTExIm_eAalSAVwzIn3as04iZgF2jqPwgSk,48565
35
35
  streamlit/url_util.py,sha256=iU1lpZhzW4ZjhjBhSdw39OzixnThIsxhXpDP-ZIgUT8,3019
36
36
  streamlit/user_info.py,sha256=tvv__45d7cA6tNrGw1vHtWwc6QLtmXTM5xZoYeTs1cw,3383
37
37
  streamlit/util.py,sha256=0Phev7Lytvcy_eqIjpoGl2-7mOODwAwArY2zJpavEh8,6375
@@ -89,10 +89,10 @@ streamlit/elements/snow.py,sha256=WHqk8zmfOr5iD0R-wLlAdlIkDDbiaayguTVmA4e7V_Q,14
89
89
  streamlit/elements/spinner.py,sha256=ZMJlO-J77lpQZbRPvqJ80ur9u11dBUwJr6JgDct8TLY,2934
90
90
  streamlit/elements/text.py,sha256=-g2LYiJpP2OAdllpd7Df9rhTehIOEuiZN7-u1jwKEio,1856
91
91
  streamlit/elements/toast.py,sha256=aT_cIaQZOpG34pBGGyV7YaW0XBj1ircE5cXs2O7KzUU,4343
92
- streamlit/elements/vega_charts.py,sha256=MPRb2D8z1r0k61vLH-1GqNGIwTY2wqtkGwg5aNgQwA8,74285
92
+ streamlit/elements/vega_charts.py,sha256=rt_eZBpUoNQDV4OcLeGz6fG2-0FlzEwtXfOy_i09HGE,75825
93
93
  streamlit/elements/write.py,sha256=9kpeYFx8huqQOPR_3me2vXjXbyWwipBNpMcwp1icnHI,21021
94
94
  streamlit/elements/lib/__init__.py,sha256=Vrf1yVMOcTyhUPnYvsfyeL96Vpd5z8KoSV5ZzTcTQgU,616
95
- streamlit/elements/lib/built_in_chart_utils.py,sha256=VStm5ps5G1OqllEXkCQxzSTUUC7IY199O9zHxVvITqc,32285
95
+ streamlit/elements/lib/built_in_chart_utils.py,sha256=1Z4yHv-VnHKVsAlArlf3xa7vHrjnwrzxY5orQVPXJ7Y,34724
96
96
  streamlit/elements/lib/column_config_utils.py,sha256=-33zN3dALfvBdV0KAaLMpXNv7xwNrekCoG2r-pmr3B8,17379
97
97
  streamlit/elements/lib/column_types.py,sha256=anShsRYM3brr30bB7B-j3PBm3pJwD7dBpFz-7zwSfwY,51180
98
98
  streamlit/elements/lib/dialog.py,sha256=qaQjJNeaXanqCBtJ-rDv1vY2oCLRSiigdi7qKtYaldw,5732
@@ -529,9 +529,9 @@ streamlit/web/server/server_util.py,sha256=C3M971XFoEXTMufQLwHbZdtZOE30nWx-2WiXm
529
529
  streamlit/web/server/stats_request_handler.py,sha256=47nQHe4ETsO9QS9FAEUF8rZigU_k5eACJZw4-jc8U6c,3684
530
530
  streamlit/web/server/upload_file_request_handler.py,sha256=ftyKpARrUjOpRcFETIXuoTyOG_mo-ToOw5NI0y_W4lE,5003
531
531
  streamlit/web/server/websocket_headers.py,sha256=07SkWLcOxbyldl7UcBzrMKY9ZojypCQACiKoh5FcH7Y,1870
532
- streamlit_nightly-1.36.1.dev20240626.data/scripts/streamlit.cmd,sha256=ZEYM3vBJSp-k7vwSJ3ba5NzEk9-qHdSeLvGYAAe1mMw,676
533
- streamlit_nightly-1.36.1.dev20240626.dist-info/METADATA,sha256=d0CSSpOYbSy3pEs_wMZgyl_AG80I4NOFmoZz2A1Wvos,8531
534
- streamlit_nightly-1.36.1.dev20240626.dist-info/WHEEL,sha256=_4XEmVmaBFWtekSGrbfOGNjC2I5lUr0lZSRblBllIFA,109
535
- streamlit_nightly-1.36.1.dev20240626.dist-info/entry_points.txt,sha256=uNJ4DwGNXEhOK0USwSNanjkYyR-Bk7eYQbJFDrWyOgY,53
536
- streamlit_nightly-1.36.1.dev20240626.dist-info/top_level.txt,sha256=V3FhKbm7G2LnR0s4SytavrjIPNIhvcsAGXfYHAwtQzw,10
537
- streamlit_nightly-1.36.1.dev20240626.dist-info/RECORD,,
532
+ streamlit_nightly-1.36.1.dev20240627.data/scripts/streamlit.cmd,sha256=ZEYM3vBJSp-k7vwSJ3ba5NzEk9-qHdSeLvGYAAe1mMw,676
533
+ streamlit_nightly-1.36.1.dev20240627.dist-info/METADATA,sha256=HexX6Zm08shI4hezGym8T6l6roNgucozZZ2ayYn3fNM,8531
534
+ streamlit_nightly-1.36.1.dev20240627.dist-info/WHEEL,sha256=_4XEmVmaBFWtekSGrbfOGNjC2I5lUr0lZSRblBllIFA,109
535
+ streamlit_nightly-1.36.1.dev20240627.dist-info/entry_points.txt,sha256=uNJ4DwGNXEhOK0USwSNanjkYyR-Bk7eYQbJFDrWyOgY,53
536
+ streamlit_nightly-1.36.1.dev20240627.dist-info/top_level.txt,sha256=V3FhKbm7G2LnR0s4SytavrjIPNIhvcsAGXfYHAwtQzw,10
537
+ streamlit_nightly-1.36.1.dev20240627.dist-info/RECORD,,