flet-charts 0.2.0.dev35__py3-none-any.whl → 0.70.0.dev6555__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.

Potentially problematic release.


This version of flet-charts might be problematic. Click here for more details.

Files changed (46) hide show
  1. flet_charts/__init__.py +59 -17
  2. flet_charts/bar_chart.py +87 -30
  3. flet_charts/bar_chart_group.py +1 -2
  4. flet_charts/bar_chart_rod.py +36 -5
  5. flet_charts/candlestick_chart.py +269 -0
  6. flet_charts/candlestick_chart_spot.py +98 -0
  7. flet_charts/chart_axis.py +29 -9
  8. flet_charts/line_chart.py +76 -14
  9. flet_charts/line_chart_data.py +30 -5
  10. flet_charts/line_chart_data_point.py +33 -4
  11. flet_charts/matplotlib_backends/backend_flet_agg.py +16 -0
  12. flet_charts/matplotlib_chart.py +396 -36
  13. flet_charts/matplotlib_chart_with_toolbar.py +125 -0
  14. flet_charts/pie_chart.py +3 -6
  15. flet_charts/pie_chart_section.py +29 -18
  16. flet_charts/plotly_chart.py +17 -6
  17. flet_charts/radar_chart.py +214 -0
  18. flet_charts/radar_data_set.py +66 -0
  19. flet_charts/scatter_chart.py +75 -29
  20. flet_charts/scatter_chart_spot.py +44 -6
  21. flet_charts/types.py +159 -16
  22. flet_charts-0.70.0.dev6555.dist-info/METADATA +67 -0
  23. flet_charts-0.70.0.dev6555.dist-info/RECORD +47 -0
  24. flutter/flet_charts/CHANGELOG.md +1 -1
  25. flutter/flet_charts/LICENSE +1 -1
  26. flutter/flet_charts/analysis_options.yaml +1 -1
  27. flutter/flet_charts/lib/src/bar_chart.dart +2 -0
  28. flutter/flet_charts/lib/src/candlestick_chart.dart +129 -0
  29. flutter/flet_charts/lib/src/extension.dart +6 -0
  30. flutter/flet_charts/lib/src/radar_chart.dart +104 -0
  31. flutter/flet_charts/lib/src/scatter_chart.dart +22 -21
  32. flutter/flet_charts/lib/src/utils/bar_chart.dart +137 -73
  33. flutter/flet_charts/lib/src/utils/candlestick_chart.dart +118 -0
  34. flutter/flet_charts/lib/src/utils/charts.dart +12 -0
  35. flutter/flet_charts/lib/src/utils/line_chart.dart +15 -3
  36. flutter/flet_charts/lib/src/utils/pie_chart.dart +2 -1
  37. flutter/flet_charts/lib/src/utils/radar_chart.dart +90 -0
  38. flutter/flet_charts/lib/src/utils/scatter_chart.dart +22 -21
  39. flutter/flet_charts/pubspec.lock +85 -71
  40. flutter/flet_charts/pubspec.yaml +10 -9
  41. flet_charts-0.2.0.dev35.dist-info/METADATA +0 -69
  42. flet_charts-0.2.0.dev35.dist-info/RECORD +0 -38
  43. flutter/flet_charts/README.md +0 -3
  44. {flet_charts-0.2.0.dev35.dist-info → flet_charts-0.70.0.dev6555.dist-info}/WHEEL +0 -0
  45. {flet_charts-0.2.0.dev35.dist-info → flet_charts-0.70.0.dev6555.dist-info}/licenses/LICENSE +0 -0
  46. {flet_charts-0.2.0.dev35.dist-info → flet_charts-0.70.0.dev6555.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,28 @@
1
1
  import re
2
2
  import xml.etree.ElementTree as ET
3
3
  from dataclasses import field
4
+ from typing import Any, Optional
4
5
 
5
6
  import flet as ft
6
7
 
8
+ _PLOTLY_IMPORT_ERROR: Optional[ImportError] = None
9
+
7
10
  try:
8
11
  from plotly.graph_objects import Figure
9
- except ImportError as e:
10
- raise Exception(
11
- 'Install "plotly" Python package to use PlotlyChart control.'
12
- ) from e
12
+ except ImportError as e: # pragma: no cover - depends on optional dependency
13
+ Figure = Any # type: ignore[assignment]
14
+ _PLOTLY_IMPORT_ERROR = e
13
15
 
14
16
  __all__ = ["PlotlyChart"]
15
17
 
16
18
 
19
+ def _require_plotly() -> None:
20
+ if _PLOTLY_IMPORT_ERROR is not None:
21
+ raise ModuleNotFoundError(
22
+ 'Install "plotly" Python package to use PlotlyChart control.'
23
+ ) from _PLOTLY_IMPORT_ERROR
24
+
25
+
17
26
  @ft.control(kw_only=True)
18
27
  class PlotlyChart(ft.Container):
19
28
  """
@@ -28,8 +37,9 @@ class PlotlyChart(ft.Container):
28
37
 
29
38
  figure: Figure = field(metadata={"skip": True})
30
39
  """
31
- Plotly figure to draw -
32
- an instance of [`plotly.graph_objects.Figure`](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html).
40
+ Plotly figure to draw.
41
+
42
+ The value is an instance of [`plotly.graph_objects.Figure`](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html).
33
43
  """
34
44
 
35
45
  original_size: bool = False
@@ -40,6 +50,7 @@ class PlotlyChart(ft.Container):
40
50
  """
41
51
 
42
52
  def init(self):
53
+ _require_plotly()
43
54
  self.alignment = ft.Alignment.CENTER
44
55
  self.__img = ft.Image(fit=ft.BoxFit.FILL)
45
56
  self.content = self.__img
@@ -0,0 +1,214 @@
1
+ from dataclasses import dataclass, field
2
+ from enum import Enum
3
+ from typing import Optional
4
+
5
+ import flet as ft
6
+ from flet_charts.radar_data_set import RadarDataSet
7
+ from flet_charts.types import ChartEventType
8
+
9
+ __all__ = ["RadarChart", "RadarChartEvent", "RadarChartTitle", "RadarShape"]
10
+
11
+
12
+ class RadarShape(Enum):
13
+ """Shape of the radar grid and data polygons."""
14
+
15
+ CIRCLE = "circle"
16
+ """Draws radial circles for the grid and data outlines."""
17
+
18
+ POLYGON = "polygon"
19
+ """Draws straight-edged polygons for the grid and data outlines."""
20
+
21
+
22
+ @ft.control("RadarChartTitle")
23
+ class RadarChartTitle(ft.BaseControl):
24
+ """
25
+ Custom title configuration displayed around a [`RadarChart`][(p).].
26
+ """
27
+
28
+ text: str = ""
29
+ """
30
+ The text displayed for the title.
31
+ """
32
+
33
+ angle: ft.Number = 0
34
+ """
35
+ Rotation angle (in degrees) applied to the title.
36
+ """
37
+
38
+ position_percentage_offset: Optional[ft.Number] = None
39
+ """
40
+ Defines the relative distance of this title from the chart center.
41
+
42
+ - `0` draws this title near the inside edge of each section.
43
+ - `1` draws this title near the outside edge of each section.
44
+
45
+ Must be between `0` and `1` (inclusive), if set.
46
+
47
+ Note:
48
+ If set, it takes precedence over the parent
49
+ [`RadarChart.title_position_percentage_offset`][(p).] value.
50
+ """
51
+
52
+ text_spans: Optional[list[ft.TextSpan]] = None
53
+ """
54
+ Inline spans appended to the title.
55
+ """
56
+
57
+
58
+ @dataclass
59
+ class RadarChartEvent(ft.Event["RadarChart"]):
60
+ """
61
+ Event raised for interactions with a [`RadarChart`][(p).].
62
+ """
63
+
64
+ type: ChartEventType
65
+ """
66
+ The touch or pointer event that occurred.
67
+ """
68
+
69
+ data_set_index: Optional[int] = None
70
+ """
71
+ The index of the touched data set, if any.
72
+ """
73
+
74
+ entry_index: Optional[int] = None
75
+ """
76
+ The index of the touched radar entry, if any.
77
+ """
78
+
79
+ entry_value: Optional[ft.Number] = None
80
+ """
81
+ The value of the touched radar entry, if any.
82
+ """
83
+
84
+
85
+ @ft.control("RadarChart")
86
+ class RadarChart(ft.LayoutControl):
87
+ """
88
+ A radar chart made of multiple datasets.
89
+ """
90
+
91
+ data_sets: list[RadarDataSet] = field(default_factory=list)
92
+ """
93
+ A list of [`RadarDataSet`][(p).] controls rendered on the chart.
94
+ """
95
+
96
+ titles: list[RadarChartTitle] = field(default_factory=list)
97
+ """
98
+ The titles shown around this chart, matching the number of entries per set.
99
+ """
100
+
101
+ title_text_style: Optional[ft.TextStyle] = None
102
+ """
103
+ The text style applied to titles around this chart.
104
+ """
105
+
106
+ title_position_percentage_offset: ft.Number = 0.2
107
+ """
108
+ Defines the relative distance of titles from the chart center.
109
+
110
+ - `0` draws titles near the inside edge of each section.
111
+ - `1` draws titles near the outside edge of each section.
112
+
113
+ Must be between `0` and `1` (inclusive).
114
+
115
+ Raises:
116
+ ValueError: If set to a value less than `0` or greater than `1`.
117
+ """
118
+
119
+ radar_bgcolor: ft.ColorValue = ft.Colors.TRANSPARENT
120
+ """
121
+ The background color of the radar area.
122
+ """
123
+
124
+ radar_border_side: ft.BorderSide = field(
125
+ default_factory=lambda: ft.BorderSide(width=2.0)
126
+ )
127
+ """
128
+ The outline drawn around the radar area.
129
+ """
130
+
131
+ radar_shape: RadarShape = RadarShape.POLYGON
132
+ """
133
+ The shape of the radar area.
134
+ """
135
+
136
+ border: Optional[ft.Border] = None
137
+ """
138
+ The border drawn around this chart.
139
+ """
140
+
141
+ center_min_value: bool = False
142
+ """
143
+ Whether minimum entry values should be positioned at the center of this chart.
144
+ """
145
+
146
+ tick_count: ft.Number = 1
147
+ """
148
+ Number of tick rings drawn from the centre to the edge.
149
+
150
+ Must be greater than or equal to `1`.
151
+
152
+ Raises:
153
+ ValueError: If set to a value less than `1`.
154
+ """
155
+
156
+ ticks_text_style: Optional[ft.TextStyle] = None
157
+ """
158
+ The text style used to draw tick labels.
159
+ """
160
+
161
+ tick_border_side: ft.BorderSide = field(
162
+ default_factory=lambda: ft.BorderSide(width=2.0)
163
+ )
164
+ """
165
+ The style of the tick rings.
166
+ """
167
+
168
+ grid_border_side: ft.BorderSide = field(
169
+ default_factory=lambda: ft.BorderSide(width=2.0)
170
+ )
171
+ """
172
+ The style of the radar grid lines.
173
+ """
174
+
175
+ animation: ft.AnimationValue = field(
176
+ default_factory=lambda: ft.Animation(
177
+ duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR
178
+ )
179
+ )
180
+ """
181
+ Controls the implicit animation applied when updating this chart.
182
+ """
183
+
184
+ interactive: bool = True
185
+ """
186
+ Enables touch interactions and event notifications.
187
+ """
188
+
189
+ long_press_duration: Optional[ft.DurationValue] = None
190
+ """
191
+ The duration before a long-press event fires.
192
+ """
193
+
194
+ touch_spot_threshold: ft.Number = 10
195
+ """
196
+ The radius (in logical pixels) used to detect nearby entries for touches.
197
+ """
198
+
199
+ on_event: Optional[ft.EventHandler[RadarChartEvent]] = None
200
+ """
201
+ Called when the chart is interacted with.
202
+ """
203
+
204
+ def init(self):
205
+ super().init()
206
+ entries_lengths = {len(ds.entries) for ds in self.data_sets}
207
+ if len(entries_lengths) > 1:
208
+ raise ValueError(
209
+ "All data sets in the data_sets list must have equal number of entries"
210
+ )
211
+ if not (0 <= self.title_position_percentage_offset <= 1):
212
+ raise ValueError("title_position_percentage_offset must be between 0 and 1")
213
+ if self.tick_count is not None and self.tick_count < 1:
214
+ raise ValueError("tick_count must be greater than or equal to 1")
@@ -0,0 +1,66 @@
1
+ from dataclasses import field
2
+ from typing import Optional
3
+
4
+ import flet as ft
5
+
6
+ __all__ = ["RadarDataSet", "RadarDataSetEntry"]
7
+
8
+
9
+ @ft.control("RadarDataSetEntry")
10
+ class RadarDataSetEntry(ft.BaseControl):
11
+ """
12
+ A single data point rendered on a [`RadarChart`][(p).].
13
+ """
14
+
15
+ value: ft.Number
16
+ """
17
+ The numeric value drawn for this entry.
18
+ """
19
+
20
+
21
+ @ft.control("RadarDataSet")
22
+ class RadarDataSet(ft.BaseControl):
23
+ """
24
+ A collection of [`RadarDataSetEntry`][(p).] drawn as a filled radar shape.
25
+ """
26
+
27
+ entries: list[RadarDataSetEntry] = field(default_factory=list)
28
+ """
29
+ The data points that compose this set.
30
+ """
31
+
32
+ fill_color: ft.ColorValue = ft.Colors.CYAN
33
+ """
34
+ The color used to fill this dataset.
35
+ """
36
+
37
+ fill_gradient: Optional[ft.Gradient] = None
38
+ """
39
+ The gradient used to fill this dataset.
40
+
41
+ Takes precedence over [`fill_color`][..].
42
+ """
43
+
44
+ border_color: ft.ColorValue = ft.Colors.CYAN
45
+ """
46
+ The color of the dataset outline.
47
+ """
48
+
49
+ border_width: ft.Number = 2.0
50
+ """
51
+ The width of the dataset outline.
52
+ """
53
+
54
+ entry_radius: ft.Number = 5.0
55
+ """
56
+ The radius of each entry.
57
+ """
58
+
59
+ def init(self):
60
+ super().init()
61
+ entries_length = len(self.entries)
62
+ if entries_length != 0 and entries_length < 3:
63
+ raise ValueError(
64
+ f"entries can contain either 0 or at least 3 items, "
65
+ f"got {entries_length}"
66
+ )
@@ -2,10 +2,9 @@ from dataclasses import dataclass, field
2
2
  from typing import Any, Optional
3
3
 
4
4
  import flet as ft
5
-
6
- from .chart_axis import ChartAxis
7
- from .scatter_chart_spot import ScatterChartSpot
8
- from .types import ChartEventType, ChartGridLines, ChartHorizontalAlignment
5
+ from flet_charts.chart_axis import ChartAxis
6
+ from flet_charts.scatter_chart_spot import ScatterChartSpot
7
+ from flet_charts.types import ChartEventType, ChartGridLines, HorizontalAlignment
9
8
 
10
9
  __all__ = ["ScatterChart", "ScatterChartEvent", "ScatterChartTooltip"]
11
10
 
@@ -24,62 +23,104 @@ class ScatterChartTooltip:
24
23
  The tooltip's border radius.
25
24
  """
26
25
 
27
- padding: Optional[ft.PaddingValue] = None
26
+ padding: ft.PaddingValue = field(
27
+ default_factory=lambda: ft.Padding.symmetric(vertical=8, horizontal=16)
28
+ )
28
29
  """
29
30
  Applies a padding for showing contents inside the tooltip.
30
31
  """
31
32
 
32
- max_width: Optional[ft.Number] = None
33
+ max_width: ft.Number = 120
33
34
  """
34
35
  Restricts the tooltip's width.
35
36
  """
36
37
 
37
- rotate_angle: Optional[ft.Number] = None
38
+ rotation: ft.Number = 0.0
38
39
  """
39
40
  The tooltip's rotation angle in degrees.
40
41
  """
41
42
 
42
- horizontal_offset: Optional[ft.Number] = None
43
+ horizontal_offset: ft.Number = 0
43
44
  """
44
45
  Applies horizontal offset for showing tooltip.
45
46
  """
46
47
 
47
- horizontal_alignment: Optional[ChartHorizontalAlignment] = None
48
+ horizontal_alignment: HorizontalAlignment = HorizontalAlignment.CENTER
48
49
  """
49
50
  The tooltip's horizontal alignment.
50
51
  """
51
52
 
52
- border_side: Optional[ft.BorderSide] = None
53
+ border_side: ft.BorderSide = field(default_factory=lambda: ft.BorderSide.none())
53
54
  """
54
55
  The tooltip's border side.
55
56
  """
56
57
 
57
- fit_inside_horizontally: Optional[bool] = None
58
+ fit_inside_horizontally: bool = False
58
59
  """
59
60
  Forces the tooltip to shift horizontally inside the chart, if overflow happens.
60
61
  """
61
62
 
62
- fit_inside_vertically: Optional[bool] = None
63
+ fit_inside_vertically: bool = False
63
64
  """
64
65
  Forces the tooltip to shift vertically inside the chart, if overflow happens.
65
66
  """
66
67
 
68
+ def copy(
69
+ self,
70
+ *,
71
+ bgcolor: Optional[ft.ColorValue] = None,
72
+ border_radius: Optional[ft.BorderRadiusValue] = None,
73
+ padding: Optional[ft.PaddingValue] = None,
74
+ max_width: Optional[ft.Number] = None,
75
+ rotation: Optional[ft.Number] = None,
76
+ horizontal_offset: Optional[ft.Number] = None,
77
+ horizontal_alignment: Optional[HorizontalAlignment] = None,
78
+ border_side: Optional[ft.BorderSide] = None,
79
+ fit_inside_horizontally: Optional[bool] = None,
80
+ fit_inside_vertically: Optional[bool] = None,
81
+ ) -> "ScatterChartTooltip":
82
+ """
83
+ Returns a copy of this object with the specified properties overridden.
84
+ """
85
+ return ScatterChartTooltip(
86
+ bgcolor=bgcolor if bgcolor is not None else self.bgcolor,
87
+ border_radius=border_radius
88
+ if border_radius is not None
89
+ else self.border_radius,
90
+ padding=padding if padding is not None else self.padding,
91
+ max_width=max_width if max_width is not None else self.max_width,
92
+ rotation=rotation if rotation is not None else self.rotation,
93
+ horizontal_offset=horizontal_offset
94
+ if horizontal_offset is not None
95
+ else self.horizontal_offset,
96
+ horizontal_alignment=horizontal_alignment
97
+ if horizontal_alignment is not None
98
+ else self.horizontal_alignment,
99
+ border_side=border_side if border_side is not None else self.border_side,
100
+ fit_inside_horizontally=fit_inside_horizontally
101
+ if fit_inside_horizontally is not None
102
+ else self.fit_inside_horizontally,
103
+ fit_inside_vertically=fit_inside_vertically
104
+ if fit_inside_vertically is not None
105
+ else self.fit_inside_vertically,
106
+ )
107
+
67
108
 
68
109
  @dataclass
69
110
  class ScatterChartEvent(ft.Event["ScatterChart"]):
70
111
  type: ChartEventType
71
112
  """
72
- Type of the event (e.g. tapDown, panUpdate)
113
+ The type of the event that occurred.
73
114
  """
74
115
 
75
116
  spot_index: Optional[int] = None
76
117
  """
77
- Index of the touched spot, if any
118
+ The index of the touched spot, if any.
78
119
  """
79
120
 
80
121
 
81
122
  @ft.control("ScatterChart")
82
- class ScatterChart(ft.ConstrainedControl):
123
+ class ScatterChart(ft.LayoutControl):
83
124
  """
84
125
  A scatter chart control.
85
126
 
@@ -99,9 +140,6 @@ class ScatterChart(ft.ConstrainedControl):
99
140
  )
100
141
  """
101
142
  Controls chart implicit animation.
102
-
103
- Value is of [`AnimationValue`](https://flet.dev/docs/reference/types/animationvalue)
104
- type.
105
143
  """
106
144
 
107
145
  interactive: bool = True
@@ -109,11 +147,6 @@ class ScatterChart(ft.ConstrainedControl):
109
147
  Enables automatic tooltips when hovering chart bars.
110
148
  """
111
149
 
112
- handle_built_in_touches: bool = True
113
- """
114
- Whether to show a tooltip popup on top of the spots if a touch occurs.
115
- """
116
-
117
150
  long_press_duration: Optional[ft.DurationValue] = None
118
151
  """
119
152
  The duration of a long press on the chart.
@@ -139,22 +172,22 @@ class ScatterChart(ft.ConstrainedControl):
139
172
  Controls drawing of chart's vertical lines.
140
173
  """
141
174
 
142
- left_axis: ChartAxis = field(default_factory=lambda: ChartAxis())
175
+ left_axis: Optional[ChartAxis] = None
143
176
  """
144
177
  Configures the appearance of the left axis, its title and labels.
145
178
  """
146
179
 
147
- top_axis: ChartAxis = field(default_factory=lambda: ChartAxis())
180
+ top_axis: Optional[ChartAxis] = None
148
181
  """
149
182
  Configures the appearance of the top axis, its title and labels.
150
183
  """
151
184
 
152
- right_axis: ChartAxis = field(default_factory=lambda: ChartAxis())
185
+ right_axis: Optional[ChartAxis] = None
153
186
  """
154
187
  Configures the appearance of the right axis, its title and labels.
155
188
  """
156
189
 
157
- bottom_axis: ChartAxis = field(default_factory=lambda: ChartAxis())
190
+ bottom_axis: Optional[ChartAxis] = None
158
191
  """
159
192
  Configures the appearance of the bottom axis, its title and labels.
160
193
  """
@@ -189,14 +222,27 @@ class ScatterChart(ft.ConstrainedControl):
189
222
  The maximum displayed value for Y axis.
190
223
  """
191
224
 
192
- tooltip: Optional[ScatterChartTooltip] = None
225
+ tooltip: ScatterChartTooltip = field(default_factory=lambda: ScatterChartTooltip())
193
226
  """
194
227
  The tooltip configuration for the chart.
195
228
  """
196
229
 
230
+ show_tooltips_for_selected_spots_only: bool = False
231
+ """
232
+ Whether to permanently and only show the tooltips of spots with their
233
+ [`selected`][(p).ScatterChartSpot.selected] property set to `True`.
234
+ """
235
+
236
+ rotation_quarter_turns: ft.Number = 0
237
+ """
238
+ Number of quarter turns (90-degree increments) to rotate the chart.
239
+ Ex: `1` rotates the chart `90` degrees clockwise,
240
+ `2` rotates `180` degrees and `0` for no rotation.
241
+ """
242
+
197
243
  on_event: Optional[ft.EventHandler[ScatterChartEvent]] = None
198
244
  """
199
- Fires when an event occurs on the chart.
245
+ Called when an event occurs on this chart.
200
246
  """
201
247
 
202
248
  def __post_init__(self, ref: Optional[ft.Ref[Any]]):
@@ -2,8 +2,7 @@ from dataclasses import dataclass, field
2
2
  from typing import Any, Optional, Union
3
3
 
4
4
  import flet as ft
5
-
6
- from .types import ChartDataPointTooltip, ChartPointShape
5
+ from flet_charts.types import ChartDataPointTooltip, ChartPointShape
7
6
 
8
7
  __all__ = ["ScatterChartSpot", "ScatterChartSpotTooltip"]
9
8
 
@@ -21,6 +20,37 @@ class ScatterChartSpotTooltip(ChartDataPointTooltip):
21
20
  When `None`, defaults to [`ScatterChartSpot.y`][(p).].
22
21
  """
23
22
 
23
+ bottom_margin: ft.Number = 8
24
+ """
25
+ The bottom space from the spot.
26
+ """
27
+
28
+ def copy(
29
+ self,
30
+ *,
31
+ text: Optional[str] = None,
32
+ text_style: Optional[ft.TextStyle] = None,
33
+ text_align: Optional[ft.TextAlign] = None,
34
+ text_spans: Optional[list[ft.TextSpan]] = None,
35
+ rtl: Optional[bool] = None,
36
+ bottom_margin: Optional[float] = None,
37
+ ) -> "ScatterChartSpotTooltip":
38
+ """
39
+ Returns a copy of this object with the specified properties overridden.
40
+ """
41
+ return ScatterChartSpotTooltip(
42
+ text=text if text is not None else self.text,
43
+ text_style=text_style if text_style is not None else self.text_style,
44
+ text_align=text_align if text_align is not None else self.text_align,
45
+ text_spans=text_spans.copy()
46
+ if text_spans is not None
47
+ else (self.text_spans.copy() if self.text_spans is not None else None),
48
+ rtl=rtl if rtl is not None else self.rtl,
49
+ bottom_margin=bottom_margin
50
+ if bottom_margin is not None
51
+ else self.bottom_margin,
52
+ )
53
+
24
54
 
25
55
  @ft.control("ScatterChartSpot")
26
56
  class ScatterChartSpot(ft.BaseControl):
@@ -72,10 +102,10 @@ class ScatterChartSpot(ft.BaseControl):
72
102
 
73
103
  selected: bool = False
74
104
  """
75
- TBD
105
+ Whether to treat this spot as selected.
76
106
  """
77
107
 
78
- tooltip: ScatterChartSpotTooltip = field(
108
+ tooltip: Union[ScatterChartSpotTooltip, str] = field(
79
109
  default_factory=lambda: ScatterChartSpotTooltip()
80
110
  )
81
111
  """
@@ -87,12 +117,12 @@ class ScatterChartSpot(ft.BaseControl):
87
117
  Wether to show the tooltip.
88
118
  """
89
119
 
90
- label_text: Optional[str] = None
120
+ label_text: str = ""
91
121
  """
92
122
  TBD
93
123
  """
94
124
 
95
- label_style: Optional[ft.TextStyle] = None
125
+ label_text_style: ft.TextStyle = field(default_factory=lambda: ft.TextStyle())
96
126
  """
97
127
  TBD
98
128
  """
@@ -101,3 +131,11 @@ class ScatterChartSpot(ft.BaseControl):
101
131
  """
102
132
  TBD
103
133
  """
134
+
135
+ def before_update(self):
136
+ super().before_update()
137
+ self._internals["tooltip"] = (
138
+ ScatterChartSpotTooltip(text=self.tooltip)
139
+ if isinstance(self.tooltip, str)
140
+ else self.tooltip
141
+ )